package com.arms.api.aichat.controller;

import com.arms.api.aichat.domain.ChatMessage;
import com.arms.api.aichat.domain.ChatRoom;
import com.arms.api.aichat.dto.CardContextItem;
import com.arms.api.aichat.dto.ChatMessageRequest;
import com.arms.api.aichat.dto.ChatRoomRequest;
import com.arms.api.aichat.dto.ChatRoomUpdateRequest;
import com.arms.api.aichat.dto.LastSelectionRequest;
import com.arms.api.aichat.dto.RagDocsRequest;
import com.arms.api.aichat.service.AiChatService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;

import java.util.List;

@RestController
@RequestMapping("/auth-user/api/aichat")
@RequiredArgsConstructor
@Slf4j
public class AiChatController {

    private final AiChatService aiChatService;

    /**
     * 새 대화방 생성
     * POST /auth-user/api/aichat/rooms
     */
    @PostMapping("/rooms")
    public Mono<ResponseEntity<ChatRoom>> createRoom(
            @AuthenticationPrincipal OidcUser oidcUser,
            @RequestBody(required = false) ChatRoomRequest request) {

        String userId = oidcUser.getPreferredUsername();
        String title                     = request != null ? request.getTitle()               : null;
        String pdServiceId               = request != null ? request.getPdServiceId()         : null;
        List<String> pdServiceVersionIds = request != null ? request.getPdServiceVersionIds() : null;

        log.info("Create room for user: {}, pdServiceId: {}", userId, pdServiceId);
        return Mono.fromCallable(() -> aiChatService.createRoom(userId, title, pdServiceId, pdServiceVersionIds))
                .subscribeOn(Schedulers.boundedElastic())
                .map(ResponseEntity::ok);
    }

    /**
     * 대화방 제품/버전 정보 업데이트
     * PATCH /auth-user/api/aichat/rooms/{roomId}
     */
    @PatchMapping("/rooms/{roomId}")
    public Mono<ResponseEntity<Void>> updateRoom(
            @PathVariable String roomId,
            @RequestBody ChatRoomUpdateRequest request) {

        log.info("Update room pdService: roomId={}, pdServiceId={}", roomId, request.getPdServiceId());
        return Mono.fromRunnable(() -> aiChatService.updateRoomPdService(roomId, request.getPdServiceId(), request.getPdServiceVersionIds()))
                .subscribeOn(Schedulers.boundedElastic())
                .then(Mono.just(ResponseEntity.ok().<Void>build()));
    }

    /**
     * 마지막 assistant 메시지 덮어쓰기 (체크박스 재답변용)
     * PUT /auth-user/api/aichat/rooms/{roomId}/messages/last-assistant
     */
    @PutMapping("/rooms/{roomId}/messages/last-assistant")
    public Mono<ResponseEntity<Void>> replaceLastAssistantMessage(
            @PathVariable String roomId,
            @RequestBody ChatMessageRequest request) {

        log.info("replaceLastAssistantMessage: roomId={}", roomId);
        return Mono.fromRunnable(() -> aiChatService.replaceLastAssistantMessage(roomId, request.getContent()))
                .subscribeOn(Schedulers.boundedElastic())
                .then(Mono.just(ResponseEntity.ok().<Void>build()));
    }

    /**
     * 대화내용 저장 user/assistant
     * POST /auth-user/api/aichat/rooms/{roomId}/messages
     */
    @PostMapping("/rooms/{roomId}/messages")
    public Mono<ResponseEntity<ChatMessage>> saveMessage(
            @PathVariable String roomId,
            @RequestBody ChatMessageRequest request) {

        log.info("Save message for room: {}, role: {}", roomId, request.getRole());
        return Mono.fromCallable(() -> aiChatService.saveMessage(roomId, request.getRole(), request.getContent()))
                .subscribeOn(Schedulers.boundedElastic())
                .map(ResponseEntity::ok);
    }

    /**
     * 대화방 조회(history)
     * GET /auth-user/api/aichat/rooms
     */
    @GetMapping("/rooms")
    public Mono<ResponseEntity<List<ChatRoom>>> getRoom(
            @AuthenticationPrincipal OidcUser oidcUser) {

        String userId = oidcUser.getPreferredUsername();
        log.info("Get room for user: {}", userId);
        return Mono.fromCallable(() -> aiChatService.findRoomByUserId(userId))
                .subscribeOn(Schedulers.boundedElastic())
                .map(ResponseEntity::ok);
    }

    /**
     * 대화내용 조회
     * GET /auth-user/api/aichat/rooms/{roomId}/messages
     */
    @GetMapping("/rooms/{roomId}/messages")
    public Mono<ResponseEntity<List<ChatMessage>>> getMessages(
            @PathVariable String roomId){

        log.info("Get messages for room: {}", roomId);
        long start = System.currentTimeMillis();
        return Mono.fromCallable(() -> aiChatService.findMessageByRoomId(roomId))
                .subscribeOn(Schedulers.boundedElastic())
                .map(messages -> {
                    log.info("[getMessages] total elapsed={}ms roomId={}", System.currentTimeMillis() - start, roomId);
                    return ResponseEntity.ok(messages);
                });
    }

    /**
     * 대화방 삭제
     * DELETE /auth-user/api/aichat/rooms/{roomId}
     */
    @DeleteMapping("/rooms/{roomId}")
    public Mono<ResponseEntity<Void>> deleteRoom(
            @AuthenticationPrincipal OidcUser oidcUser,
            @PathVariable String roomId) {

        String userId = oidcUser.getPreferredUsername();
        log.info("Delete room for user: {}", userId);

        return Mono.fromRunnable(() -> aiChatService.deleteRoom(userId, roomId))
                .subscribeOn(Schedulers.boundedElastic())
                .then(Mono.just(ResponseEntity.noContent().<Void>build()));
    }

    // === RAG 문서 관련 ===

    /**
     * roomId별 RAG/Wiki 문서 저장 (질문할 때마다 덮어씀)
     * POST /auth-user/api/aichat/rooms/{roomId}/rag-docs
     */
    @PostMapping("/rooms/{roomId}/rag-docs")
    public Mono<ResponseEntity<Void>> saveRagDocs(
            @PathVariable String roomId,
            @RequestBody RagDocsRequest request) {

        log.info("Save rag docs for room: {}", roomId);
        return Mono.fromRunnable(() -> aiChatService.saveRagDocs(roomId, request))
                .subscribeOn(Schedulers.boundedElastic())
                .then(Mono.just(ResponseEntity.ok().<Void>build()));
    }

    /**
     * roomId별 RAG/Wiki 문서 조회
     * GET /auth-user/api/aichat/rooms/{roomId}/rag-docs
     */
    @GetMapping("/rooms/{roomId}/rag-docs")
    public Mono<ResponseEntity<RagDocsRequest>> findRagDocs(
            @PathVariable String roomId) {

        log.info("Find rag docs for room: {}", roomId);
        return Mono.fromCallable(() -> {
                    RagDocsRequest result = aiChatService.findRagDocs(roomId);
                    return result != null ? result : new RagDocsRequest();
                })
                .subscribeOn(Schedulers.boundedElastic())
                .map(ResponseEntity::ok);
    }

    // === 카드 영역 관련 ===

    /**
     * 카드 영역 조회 (입력창 하단, 고정 추천 카드)
     * GET /auth-user/api/aichat/cards/context
     */
    @GetMapping("/cards/context")
    public Mono<ResponseEntity<List<CardContextItem>>> getCardContext(
            @AuthenticationPrincipal OidcUser oidcUser) {

        String userId = oidcUser.getPreferredUsername();
        return Mono.fromCallable(() -> aiChatService.findCardContext(userId))
                .subscribeOn(Schedulers.boundedElastic())
                .map(ResponseEntity::ok);
    }

    // === 마지막 선택 관련 ===

    /**
     * 마지막으로 선택한 pdService, pdServiceVersion 저장
     * POST /auth-user/api/aichat/last-selection
     */
    @PostMapping("/last-selection")
    public Mono<ResponseEntity<Void>> saveLastSelection(
            @AuthenticationPrincipal OidcUser oidcUser,
            @RequestBody LastSelectionRequest request) {

        String userId = oidcUser.getPreferredUsername();
        return Mono.fromRunnable(() -> aiChatService.saveLastSelection(userId, request.getPdServiceId(), request.getPdServiceVersionIds()))
                .subscribeOn(Schedulers.boundedElastic())
                .then(Mono.just(ResponseEntity.ok().<Void>build()));
    }

    /**
     * 마지막으로 선택한 pdService, pdServiceVersion 조회
     * GET /auth-user/api/aichat/last-selection
     */
    @GetMapping("/last-selection")
    public Mono<ResponseEntity<LastSelectionRequest>> findLastSelection(
            @AuthenticationPrincipal OidcUser oidcUser) {

        String userId = oidcUser.getPreferredUsername();
        return Mono.fromCallable(() -> aiChatService.findLastSelection(userId))
                .subscribeOn(Schedulers.boundedElastic())
                .map(ResponseEntity::ok);
    }

    /**
     * 마지막으로 선택한 pdService, pdServiceVersion 삭제
     * DELETE /auth-user/api/aichat/last-selection
     */
    @DeleteMapping("/last-selection")
    public Mono<ResponseEntity<Void>> deleteLastSelection(
            @AuthenticationPrincipal OidcUser oidcUser) {

        String userId = oidcUser.getPreferredUsername();
        return Mono.fromRunnable(() -> aiChatService.deleteLastSelection(userId))
                .subscribeOn(Schedulers.boundedElastic())
                .then(Mono.just(ResponseEntity.noContent().<Void>build()));
    }
}
