package com.caliverse.admin.domain.service;

import com.caliverse.admin.domain.dao.admin.MailMapper;
import com.caliverse.admin.domain.entity.AI.AIRequestType;
import com.caliverse.admin.domain.entity.AI.AIRole;
import com.caliverse.admin.domain.entity.Mail;
import com.caliverse.admin.domain.request.AIRequest;
import com.caliverse.admin.domain.request.LogGenericRequest;
import com.caliverse.admin.domain.request.OpenAIRequest;
import com.caliverse.admin.domain.response.AIResponse;
import com.caliverse.admin.domain.response.OpenAIResponse;
import com.caliverse.admin.global.common.code.CommonCode;
import com.caliverse.admin.global.common.constants.CommonConstants;
import com.caliverse.admin.global.common.utils.CommonUtils;
import com.caliverse.admin.logs.Indicatordomain.GenericMongoLog;
import com.caliverse.admin.logs.logservice.businesslogservice.BusinessLogGenericService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
@RequiredArgsConstructor
public class AIService {
    @Autowired
    private ObjectMapper mapper;

    private final OpenAIService openAIService;
    private final BusinessLogGenericService businessLogGenericService;
    private final MailMapper mailMapper;

    public AIResponse aiMessageAnalyze(AIRequest dataRequest){
        List<Map<String,String>> messages = initMessage();

        List<?> data = getDataList(dataRequest.getType(), dataRequest.getConditions());

        messages = splitDataToMessages(messages, data, dataRequest.getMessage());

        OpenAIRequest openAIRequest = new OpenAIRequest();
        openAIRequest.setMessages(messages);

        OpenAIResponse result = openAIService.askOpenAI(openAIRequest);
        log.info(result.getChoices().get(0).getMessage().getContent());
        return AIResponse.builder()
                .resultData(AIResponse.ResultData.builder()
                        .result(result.getChoices().get(0).getMessage().getContent())
                        .build())
                .status(CommonCode.SUCCESS.getHttpStatus())
                .result(CommonCode.SUCCESS.getResult())
                .build();
    }

    private List<Map<String, String>> splitDataToMessages(List<Map<String,String>> messages, List<?> dataList, String userMessage) {
        String dataJson;
        try {
            dataJson = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(dataList);
        } catch (JsonProcessingException e) {
            throw new RuntimeException("JSON 변환 실패", e);
        }
        messages.add(getAIMessage(AIRole.user, messageMerge(userMessage, dataJson)));

        return messages;
    }

    private String messageMerge(String message, String data){
        return String.format("사용자 질문: %s\n\n아래는 시스템이 제공하는 데이터입니다.\n%s", message, data);
    }

    private List<Map<String,String>> initMessage(){
        List<Map<String,String>> messages = new ArrayList<>();
        messages.add(getAIMessage(AIRole.system,
                """
                            너는 프론트엔드 게시용 데이터를 생성하는 게임 데이터 분석 AI야. \
                            사용자는 게임 로그 데이터와 함께 다양한 질문을 보낼 수 있어. \
                            너는 항상 HTML 또는 React 코드 형식으로 응답해야 해. \
                            응답에는 반드시 다음 항목을 포함해줘: \
                            1) 분석된 내용 설명 \
                            2) 분석된 요약 결과 (표 또는 문단) \
                            3) 시각화 차트 (예: bar chart, pie chart 등) \
                            응답은 반드시 한국어로 작성해. \
                            절대로 파이썬, Java, Node.js 코드 같은 것은 포함하지 마. \
                            사용자의 웹에 그대로 게시될 수 있는 코드만 생성해. \
                            React를 쓸 경우, React 18 기준 코드로 TailwindCSS 기반의 스타일을 사용해줘.
                        """));

        return messages;
    }

    private List<?> getDataList(AIRequestType type, Map<String, Object> conditions){
        switch (type){
            case BUSINESS_LOG -> {
                LogGenericRequest logReq = mapper.convertValue(conditions, LogGenericRequest.class);
                List<GenericMongoLog> logs = businessLogGenericService.loadBusinessLogData(logReq, GenericMongoLog.class);
                return logs;
            }
            case MAIL -> {
                List<Mail> mailList = mailMapper.getMailList(conditions);
                return mailList;
            }
            default -> throw new RuntimeException("Not Type");
        }
    }

    private static Map<String, String> getAIMessage(AIRole role, String message){
        return Map.of("role", role.toString(), "content", message);
    }
}
