package com.caliverse.admin.domain.service;

import com.caliverse.admin.domain.request.OpenAIRequest;
import com.caliverse.admin.domain.response.OpenAIResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.http.*;

import java.io.File;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RequiredArgsConstructor
@Service
@Slf4j
public class OpenAIService {
    private final RestTemplate restTemplate;

    @Value("${open-ai.url}")
    private String api_url;

    @Value("${open-ai.key}")
    private String api_key;

    @Value("${open-ai.chatModel}")
    private String api_chat_model;

    @Value("${open-ai.assistantsModel}")
    private String api_assistants_model;

    public OpenAIResponse askOpenAI(OpenAIRequest request) {
        request.setModel(api_chat_model);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.setBearerAuth(api_key);

        HttpEntity<OpenAIRequest> entity = new HttpEntity<>(request, headers);

        ResponseEntity<OpenAIResponse> response = restTemplate.exchange(
                api_url + "chat/completions",
                HttpMethod.POST,
                entity,
                OpenAIResponse.class
        );

        return response.getBody();
    }

    // 파일 업로드 메서드
    public String uploadFile(String filePath) {
        String url = "https://api.openai.com/v1/files";

        HttpHeaders headers = new HttpHeaders();
        headers.setBearerAuth(api_key);
        headers.setContentType(MediaType.MULTIPART_FORM_DATA);

        MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
        body.add("file", new FileSystemResource(new File(filePath)));
        body.add("purpose", "assistants");

        HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);

        ResponseEntity<Map> response = restTemplate.exchange(
                url,
                HttpMethod.POST,
                requestEntity,
                Map.class
        );

        log.info("File uploaded successfully: {}", response.getBody());
        return (String) response.getBody().get("id");
    }

    // Assistant 생성 메서드
    public String createAssistant(String name, String instructions) {
        String url = "https://api.openai.com/v1/assistants";

        HttpHeaders headers = new HttpHeaders();
        headers.setBearerAuth(api_key);
        headers.setContentType(MediaType.APPLICATION_JSON);

        Map<String, Object> body = new HashMap<>();
        body.put("model", api_assistants_model);
        body.put("name", name);
        body.put("instructions", instructions);
        body.put("tools", List.of(Map.of("type", "retrieval")));

        HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(body, headers);

        ResponseEntity<Map> response = restTemplate.exchange(
                url,
                HttpMethod.POST,
                requestEntity,
                Map.class
        );

        log.info("Assistant created successfully: {}", response.getBody());
        return (String) response.getBody().get("id");
    }

    // Thread 생성 메서드
    public String createThread() {
        String url = "https://api.openai.com/v1/threads";

        HttpHeaders headers = new HttpHeaders();
        headers.setBearerAuth(api_key);
        headers.setContentType(MediaType.APPLICATION_JSON);

        Map<String, Object> body = new HashMap<>();

        HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(body, headers);

        ResponseEntity<Map> response = restTemplate.exchange(
                url,
                HttpMethod.POST,
                requestEntity,
                Map.class
        );

        log.info("Thread created successfully: {}", response.getBody());
        return (String) response.getBody().get("id");
    }

    // Thread에 메시지 추가 메서드
    public String addMessageToThread(String threadId, String content, String fileId) {
        String url = "https://api.openai.com/v1/threads/" + threadId + "/messages";

        HttpHeaders headers = new HttpHeaders();
        headers.setBearerAuth(api_key);
        headers.setContentType(MediaType.APPLICATION_JSON);

        Map<String, Object> body = new HashMap<>();
        body.put("role", "user");
        body.put("content", content);

        if (fileId != null && !fileId.isEmpty()) {
            body.put("file_ids", Collections.singletonList(fileId));
        }

        HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(body, headers);

        ResponseEntity<Map> response = restTemplate.exchange(
                url,
                HttpMethod.POST,
                requestEntity,
                Map.class
        );

        log.info("Message added to thread successfully: {}", response.getBody());
        return (String) response.getBody().get("id");
    }

    // Run 실행 메서드
    public String startRun(String threadId, String assistantId) {
        String url = "https://api.openai.com/v1/threads/" + threadId + "/runs";

        HttpHeaders headers = new HttpHeaders();
        headers.setBearerAuth(api_key);
        headers.setContentType(MediaType.APPLICATION_JSON);

        Map<String, Object> body = new HashMap<>();
        body.put("assistant_id", assistantId);

        HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(body, headers);

        ResponseEntity<Map> response = restTemplate.exchange(
                url,
                HttpMethod.POST,
                requestEntity,
                Map.class
        );

        log.info("Run started successfully: {}", response.getBody());
        return (String) response.getBody().get("id");
    }

    // Run 상태 확인 메서드
    public Map<String, Object> checkRunStatus(String threadId, String runId) {
        String url = "https://api.openai.com/v1/threads/" + threadId + "/runs/" + runId;

        HttpHeaders headers = new HttpHeaders();
        headers.setBearerAuth(api_key);

        HttpEntity<Void> requestEntity = new HttpEntity<>(headers);

        ResponseEntity<Map> response = restTemplate.exchange(
                url,
                HttpMethod.GET,
                requestEntity,
                Map.class
        );

        log.debug("Run status: {}", response.getBody());
        return response.getBody();
    }

    // Thread의 메시지 목록 조회 메서드
    public List<Map<String, Object>> listMessages(String threadId) {
        String url = "https://api.openai.com/v1/threads/" + threadId + "/messages";

        HttpHeaders headers = new HttpHeaders();
        headers.setBearerAuth(api_key);

        HttpEntity<Void> requestEntity = new HttpEntity<>(headers);

        ResponseEntity<Map> response = restTemplate.exchange(
                url,
                HttpMethod.GET,
                requestEntity,
                Map.class
        );

        log.debug("Thread messages: {}", response.getBody());
        return (List<Map<String, Object>>) response.getBody().get("data");
    }

    // 마지막 Assistant 메시지 추출 메서드
    public String extractLastAssistantMessage(String threadId) {
        List<Map<String, Object>> messages = listMessages(threadId);

        for (Map<String, Object> message : messages) {
            if ("assistant".equals(message.get("role"))) {
                List<Map<String, Object>> content = (List<Map<String, Object>>) message.get("content");
                if (content != null && !content.isEmpty()) {
                    for (Map<String, Object> contentItem : content) {
                        if ("text".equals(contentItem.get("type"))) {
                            Map<String, Object> text = (Map<String, Object>) contentItem.get("text");
                            return (String) text.get("value");
                        }
                    }
                }
                break;  // 가장 최신 assistant 메시지만 처리
            }
        }

        return "No assistant response found";
    }

    // 파일 삭제 메서드
    public boolean deleteFile(String fileId) {
        String url = "https://api.openai.com/v1/files/" + fileId;

        HttpHeaders headers = new HttpHeaders();
        headers.setBearerAuth(api_key);

        HttpEntity<Void> requestEntity = new HttpEntity<>(headers);

        try {
            ResponseEntity<Map> response = restTemplate.exchange(
                    url,
                    HttpMethod.DELETE,
                    requestEntity,
                    Map.class
            );

            log.info("File deleted successfully: {}", response.getBody());
            return true;
        } catch (Exception e) {
            log.error("Error deleting file: {}", e.getMessage());
            return false;
        }
    }

    // Assistant 가져오기 또는 생성 메서드
    public String getOrCreateAssistant() {
        String url = "https://api.openai.com/v1/assistants";

        HttpHeaders headers = new HttpHeaders();
        headers.setBearerAuth(api_key);

        HttpEntity<Void> requestEntity = new HttpEntity<>(headers);

        ResponseEntity<Map> response = restTemplate.exchange(
                url,
                HttpMethod.GET,
                requestEntity,
                Map.class
        );

        List<Map<String, Object>> assistants = (List<Map<String, Object>>) response.getBody().get("data");

        // 데이터 분석 어시스턴트 찾기
        for (Map<String, Object> assistant : assistants) {
            if ("Data Analyzer".equals(assistant.get("name"))) {
                return (String) assistant.get("id");
            }
        }

        // 없으면 새로 생성
        return createAssistant("Data Analyzer",
                "You are a data analysis assistant. Analyze the provided JSON data and generate visualizations. " +
                        "Your responses should be in HTML format with appropriate visualizations using charts. " +
                        "Focus on identifying patterns, trends, and insights from the data. " +
                        "Use Korean language for all responses.");
    }

    // 전체 비동기 프로세스 실행 및 결과 대기 메서드
    public String processDataAnalysisAndWait(String filePath, String question) {
        try {
            // 1. 파일 업로드
            String fileId = uploadFile(filePath);

            // 2. Assistant 얻기 또는 생성
            String assistantId = getOrCreateAssistant();

            // 3. Thread 생성
            String threadId = createThread();

            // 4. 메시지 추가
            addMessageToThread(threadId, question, fileId);

            // 5. Run 실행
            String runId = startRun(threadId, assistantId);

            // 6. 완료 대기 (최대 60초, 3초마다 체크)
            String status = "queued";
            int maxAttempts = 20;
            int attempts = 0;

            while (!status.equals("completed") && attempts < maxAttempts) {
                Thread.sleep(3000);
                Map<String, Object> runStatus = checkRunStatus(threadId, runId);
                status = (String) runStatus.get("status");

                if (status.equals("failed") || status.equals("cancelled")) {
                    throw new RuntimeException("Run failed with status: " + status);
                }

                attempts++;
            }

            if (!status.equals("completed")) {
                throw new RuntimeException("Run timed out after 60 seconds");
            }

            // 7. 응답 메시지 추출
            String result = extractLastAssistantMessage(threadId);

            // 8. 파일 정리 (선택적)
            deleteFile(fileId);

            return result;

        } catch (Exception e) {
            log.error("Error in data analysis process: {}", e.getMessage());
            throw new RuntimeException("Data analysis failed: " + e.getMessage(), e);
        }
    }
}
