package cn.com.poc.ai_data_audit.service.impl;

import cn.com.poc.agent_application.entity.BizAgentApplicationDialoguesRecordEntity;
import cn.com.poc.agent_application.entity.BizAgentApplicationGcConfigEntity;
import cn.com.poc.agent_application.service.BizAgentApplicationDialoguesRecordService;
import cn.com.poc.agent_application.service.BizAgentApplicationGcConfigService;
import cn.com.poc.ai_data_audit.dto.DataAuditCallDto;
import cn.com.poc.ai_data_audit.dto.DataAuditResult;
import cn.com.poc.ai_data_audit.dto.FileUploadDto;
import cn.com.poc.ai_data_audit.dto.FileUploadReturnDto;
import cn.com.poc.ai_data_audit.entity.AIDataAuditMatchFileNameResponse;
import cn.com.poc.ai_data_audit.entity.BizAiDataAuditFileEntity;
import cn.com.poc.ai_data_audit.service.BizAiDataAuditFileService;
import cn.com.poc.ai_data_audit.service.DataAuditService;
import cn.com.poc.common.constant.CommonConstant;
import cn.com.poc.common.utils.*;
import cn.com.poc.law.entity.motorVehicleDrivingComplaint.Plaintiff;
import cn.com.poc.ocr.entity.BizFileOcrCacheEntity;
import cn.com.poc.ocr.service.BizFileOcrCacheService;
import cn.com.poc.thirdparty.resource.demand.ai.constants.LLMRoleEnum;
import cn.com.poc.thirdparty.resource.demand.ai.entity.dialogue.Message;
import cn.com.poc.thirdparty.resource.demand.ai.entity.largemodel.LargeModelDemandResult;
import cn.com.poc.thirdparty.resource.demand.ai.entity.largemodel.LargeModelResponse;
import cn.com.poc.thirdparty.resource.demand.ai.entity.orc.minerU.MinerUOcrResult;
import cn.com.poc.thirdparty.service.LLMService;
import cn.com.yict.framemax.core.exception.BusinessException;
import cn.com.yict.framemax.core.service.impl.BaseServiceImpl;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;
import java.util.stream.Collectors;

@Service
public class DataAuditServiceImpl extends BaseServiceImpl
        implements DataAuditService {

    @Resource
    private BizAiDataAuditFileService bizAiDataAuditFileService;

    @Resource
    private LLMService llmService;

    @Resource
    private BizFileOcrCacheService bizFileOcrCacheService;

    @Resource
    private BizAgentApplicationDialoguesRecordService bizAgentApplicationDialoguesRecordService;

    @Resource
    private BizAgentApplicationGcConfigService bizAgentApplicationGcConfigService;

    final private ThreadPoolExecutor executor = new ThreadPoolExecutor(16, 64, 10, TimeUnit.SECONDS, new LinkedBlockingDeque<>(100));

    @Override
    public List fileUploadAndProcessing(List<FileUploadDto> fileUploadDtoList) throws Exception {
        fileUploadDtoList.stream().collect(Collectors.groupingBy(item -> item.getFileName()));

        // 获取单个文件的文件名
        List<String> fileNames = fileUploadDtoList.stream()
                .map(item -> item.getFileName())
                .collect(Collectors.toList());

        CompletableFuture<List<AIDataAuditMatchFileNameResponse>> extractFileFuture = CompletableFuture.supplyAsync(() -> {
            try {
                return matchOriginalTemplateAndUploadFile(fileNames);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }, executor).exceptionally(ex -> {
            return new ArrayList<AIDataAuditMatchFileNameResponse>();
        });

        CompletableFuture<MinerUOcrResult> ocrFuture = CompletableFuture.supplyAsync(() -> {
            try {
                return ocrPrase(new File("1"));
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }, executor).exceptionally(ex -> {
            return new MinerUOcrResult();
        });

        // 等待所有任务完成并获取结果
        CompletableFuture.allOf(extractFileFuture, ocrFuture).join();
        List<AIDataAuditMatchFileNameResponse> aiDataAuditMatchFileNameResponses = extractFileFuture.get();
        MinerUOcrResult minerUOcrResult = ocrFuture.get();


        Map<String, String> fileNameMap = new HashMap<>();
//        fileNameMap.put("DOC-01","Work Permit Application Details");
//        fileNameMap.put("DOC-02","Work Permit Extension Details");
        fileNameMap.put("DOC-03", "Work Method Statement");
        fileNameMap.put("DOC-04", "Safety Method Statement or Safety Plan");
        fileNameMap.put("DOC-05", "Risk Assessment");
        fileNameMap.put("DOC-06", "Work Programme");
        fileNameMap.put("DOC-07", "Location Plan");
        fileNameMap.put("DOC-08", "HKIA Contractor Safety (Construction & Maintenance) Training Record");
        fileNameMap.put("DOC-09", "HKIA BRAAS Check Form or BRAAS Exemption Declaration Form");
        fileNameMap.put("DOC-10", "Premises Endorser Declaration Form for Work Permit Application");
        fileNameMap.put("DOC-11", "OCWIP");
        fileNameMap.put("DOC-12", "Insurance");
        fileNameMap.put("DOC-13", "Pay-in-Slip for Work Permit Processing Fee");
        fileNameMap.put("DOC-14", "HKIA APM Safety Video Training and Examination Record");
        fileNameMap.put("DOC-15", "Aerodrome Safety Risk Assessment");
        fileNameMap.put("DOC-16", "System Change Request (SCR)");
        fileNameMap.put("DOC-17", "CCTV Equipment Configuration Request Form");
        fileNameMap.put("DOC-18", "Permit to Dig");
        fileNameMap.put("DOC-19", "Temporary Traffic Management Plan");

        List<AIDataAuditMatchFileNameResponse> otherList = new ArrayList<>();
        List<FileUploadReturnDto> fileUploadReturnDtoList = new ArrayList<>();

        if (fileNames.contains("Form.pdf")) {
            FileUploadReturnDto fileUploadReturnDto = new FileUploadReturnDto();
            fileUploadReturnDto.setOrginalTemplateCode("DOC-01");
            fileUploadReturnDto.setOrginalTemplateName("Work Permit Application Details");
            fileUploadReturnDto.setUploadFileName("Form.pdf");
            fileUploadReturnDtoList.add(fileUploadReturnDto);

            FileUploadReturnDto fileUploadExtensionDto = new FileUploadReturnDto();
            fileUploadExtensionDto.setOrginalTemplateCode("DOC-02");
            fileUploadExtensionDto.setOrginalTemplateName("Work Permit Extension Details");
            fileUploadExtensionDto.setUploadFileName("");
            fileUploadReturnDtoList.add(fileUploadExtensionDto);
        }else{
            throw new Exception("please upload the Form.pdf");
        }


        //执行类型匹配
        for (AIDataAuditMatchFileNameResponse aiDataAuditMatchFileNameResponse : aiDataAuditMatchFileNameResponses) {
            if (StringUtils.isBlank(aiDataAuditMatchFileNameResponse.getTemplateName())) {
                otherList.add(aiDataAuditMatchFileNameResponse);
                continue;
            }
            FileUploadReturnDto fileUploadReturnDto = new FileUploadReturnDto();
            fileUploadReturnDto.setOrginalTemplateName(aiDataAuditMatchFileNameResponse.getTemplateName());
            fileUploadReturnDto.setOrginalTemplateCode(aiDataAuditMatchFileNameResponse.getTemplateCode());
            fileUploadReturnDto.setUploadFileName(aiDataAuditMatchFileNameResponse.getUploadFileName());
            fileUploadReturnDtoList.add(fileUploadReturnDto);
        }

        for (AIDataAuditMatchFileNameResponse other : otherList) {
            FileUploadReturnDto fileUploadReturnDto = new FileUploadReturnDto();
            fileUploadReturnDto.setOrginalTemplateName("ohter");
            fileUploadReturnDto.setOrginalTemplateCode("ohter");
            fileUploadReturnDto.setUploadFileName(other.getUploadFileName());
            fileUploadReturnDtoList.add(fileUploadReturnDto);
        }
        return fileUploadReturnDtoList;
    }

    @Override
    public DataAuditResult call(DataAuditCallDto dataAuditCallDto) throws Exception {
        Long userId = BlContext.getCurrentUser().getUserId();

        String input = dataAuditCallDto.getInput();
        String dialoguesId = dataAuditCallDto.getDialoguesId();
        Assert.notNull(dataAuditCallDto.getFileId(), "file can not be null");

        //记录提问时间
        long inputTimestamp = System.currentTimeMillis();

        SSEUtil sseUtil = new SSEUtil();
        // 获取大模型配置
        String promptCode = "AIDataAuditCall";
        BizAgentApplicationGcConfigEntity documentDialoguePrompt = bizAgentApplicationGcConfigService.getByConfigCode(promptCode);
        if (documentDialoguePrompt == null || StringUtils.isBlank(documentDialoguePrompt.getConfigSystem())) {
            throw new BusinessException("获取对话提示词失败");
        }

        BizAiDataAuditFileEntity bizAiDataAuditFileEntity = bizAiDataAuditFileService.get(dataAuditCallDto.getFileId());
        BizFileOcrCacheEntity example = new BizFileOcrCacheEntity();
        example.setMd5(bizAiDataAuditFileEntity.getMd5());
        List<BizFileOcrCacheEntity> bizFileOcrCacheEntityList = bizFileOcrCacheService.findByExample(example,null);

        if(CollectionUtils.isEmpty(bizFileOcrCacheEntityList)){
            throw new BusinessException("can not file the file");
        }

        File file = DocumentLoad.downloadURLDocument(bizFileOcrCacheEntityList.get(0).getMdFileUrl());
        String fileContent="";
        try (BufferedReader br = new BufferedReader(new FileReader(file))) {
            String content;
            while ((content = br.readLine()) != null) {
                fileContent=content+fileContent;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        //组装请求参数
        List<Message> messages = buildMessagesAndRecord(dialoguesId, userId, input, null, documentDialoguePrompt.getConfigSystem().replace("${content}", fileContent));
        LargeModelResponse largeModelResponse = new LargeModelResponse();
        largeModelResponse.setModel(documentDialoguePrompt.getLargeModel());
        largeModelResponse.setMessages(messages.toArray(new Message[0]));
        largeModelResponse.setStream(true);
        BufferedReader bufferedReader = llmService.chatChunk(largeModelResponse);
        DataAuditResult dataAuditResult = textOutputStream(sseUtil, bufferedReader);

        // 保存用户输入记录
        BizAgentApplicationDialoguesRecordEntity inputRecord = new BizAgentApplicationDialoguesRecordEntity();
        inputRecord.setMemberId(userId);
        inputRecord.setContent(input);
        inputRecord.setDialogsId(dialoguesId);
        inputRecord.setRole(LLMRoleEnum.USER.getRole());
        inputRecord.setTimestamp(inputTimestamp);

        // 保存AI回复记录
        BizAgentApplicationDialoguesRecordEntity assistantRecord = new BizAgentApplicationDialoguesRecordEntity();
        assistantRecord.setMemberId(userId);
        assistantRecord.setContent(dataAuditResult.getMessage());
        assistantRecord.setReasoningContent(dataAuditResult.getReasoningContent());
        assistantRecord.setDialogsId(dialoguesId);
        assistantRecord.setRole(LLMRoleEnum.ASSISTANT.getRole());
        assistantRecord.setTimestamp(System.currentTimeMillis());

        bizAgentApplicationDialoguesRecordService.save(inputRecord);
        bizAgentApplicationDialoguesRecordService.save(assistantRecord);

        return dataAuditResult;
    }

    /**
     * 文本输出结果
     *
     * @param sseUtil
     * @param bufferedReader
     * @throws IOException
     */
    private DataAuditResult textOutputStream(SSEUtil sseUtil, BufferedReader bufferedReader) throws IOException {
        String res = "";
        StringBuilder output = new StringBuilder();
        StringBuilder reasoningContent = new StringBuilder();
        try {
            while ((res = bufferedReader.readLine()) != null) {
                if (StringUtils.isEmpty(res)) {
                    continue;
                }
                res = StringUtils.replace(res, "data: ", StringUtils.EMPTY);
                LargeModelDemandResult result = JsonUtils.deSerialize(res, LargeModelDemandResult.class);
                if (!"0".equals(result.getCode())) {
                    BusinessException ex = new BusinessException("exception/call.failure");
                    result.setMessage(ex.getMessage());
                    sseUtil.send(JsonUtils.serialize(result));
                    sseUtil.send("[DONE]");
                    sseUtil.complete();
                    throw ex;
                }
                result.setFunction(null);
                result.setDbChainResult(null);
                result.setKnowledgeContentResult(null);
                result.setMessage(result.getMessage());
                sseUtil.send(JsonUtils.serialize(result));
                if (StringUtils.isNotEmpty(result.getMessage())) {
                    output.append(result.getMessage());
                }
                if (StringUtils.isNotEmpty(result.getReasoningContent())) {
                    reasoningContent.append(result.getReasoningContent());
                }
            }
            // 关闭资源
            sseUtil.send("[DONE]");
            sseUtil.complete();
            DataAuditResult dataAuditResult = new DataAuditResult();
            dataAuditResult.setMessage(output.toString());
            dataAuditResult.setReasoningContent(reasoningContent.toString());
            return dataAuditResult;
        } catch (IOException e) {
            sseUtil.completeByError("连接断开");
            throw new BusinessException("连接断开");
        } finally {
            bufferedReader.close();
            sseUtil.complete();
        }
    }


    public List<AIDataAuditMatchFileNameResponse> matchOriginalTemplateAndUploadFile(List<String> fileNames) throws Exception {
        // 获取对话提示词
        String promptCode = "AIDataAuditMatchFileName";
        BizAgentApplicationGcConfigEntity documentDialoguePrompt = bizAgentApplicationGcConfigService.getByConfigCode(promptCode);
        if (documentDialoguePrompt == null || StringUtils.isBlank(documentDialoguePrompt.getConfigSystem())) {
            throw new BusinessException("获取对话提示词失败");
        }

        fileNames = fileNames.stream().filter(item -> !item.contains("Form.pdf")).collect(Collectors.toList());
        String prompt = documentDialoguePrompt.getConfigSystem().replace("${uploadFileName}", JSON.toJSONString(fileNames));

        //组装请求参数
        List<Message> messages = buildMessages("", null, prompt);
        LargeModelResponse largeModelResponse = new LargeModelResponse();
        largeModelResponse.setModel("deepseek-v3");//获取模型);
        largeModelResponse.setTopP(0.1f);//获取模型);
        largeModelResponse.setTemperature(0.1f);//获取模型);
        largeModelResponse.setMessages(messages.toArray(new Message[0]));
        largeModelResponse.setStream(false);
        LargeModelDemandResult chat = llmService.chat(largeModelResponse);
        Plaintiff plaintiff = new Plaintiff();
        if (ObjectUtil.isEmpty(chat) || !chat.getCode().equals("0")) {
            throw new BusinessException("获取失败");
        }
        String message = chat.getMessage().replaceAll("```json", StringUtils.EMPTY).replaceAll("```", StringUtils.EMPTY);
        List<AIDataAuditMatchFileNameResponse> aIDataAuditMatchFileNameResponses = JSON.parseArray(message, AIDataAuditMatchFileNameResponse.class);
        if (ObjectUtil.isEmpty(plaintiff)) {
            throw new BusinessException("提取失败");
        }
        return aIDataAuditMatchFileNameResponses;
    }

    private List<Message> buildMessages(String input, String fileUrl, String prompt) throws Exception {
        // 配置message
        List<Message> messages = new ArrayList<>();
        Message systemMessage = new Message();
        systemMessage.setContent(prompt);
        systemMessage.setRole(LLMRoleEnum.SYSTEM.getRole());
        messages.add(systemMessage);

        // 用户输入
        Message message = new Message();
        message.setContent(input);
        message.setRole(LLMRoleEnum.USER.getRole());
        messages.add(message);

        return messages;
    }

    private List<Message> buildMessagesAndRecord(String dialoguesId, Long userId, String input, String fileUrl, String prompt) throws Exception {

        // 配置message
        List<Message> messages = new ArrayList<>();
        Message systemMessage = new Message();
        systemMessage.setContent(prompt);
        systemMessage.setRole(LLMRoleEnum.SYSTEM.getRole());
        messages.add(systemMessage);

        // 对话记录
        BizAgentApplicationDialoguesRecordEntity recordEntity = new BizAgentApplicationDialoguesRecordEntity();
        recordEntity.setDialogsId(dialoguesId);
        recordEntity.setIsDeleted(CommonConstant.IsDeleted.N);
        recordEntity.setMemberId(userId);
        List<BizAgentApplicationDialoguesRecordEntity> recordEntities = bizAgentApplicationDialoguesRecordService.findByExample(recordEntity, null);
        if (CollectionUtils.isNotEmpty(recordEntities)) {
            for (BizAgentApplicationDialoguesRecordEntity entity : recordEntities) {
                Message message = new Message();
                message.setContent(entity.getContent());
                message.setRole(entity.getRole());
                messages.add(message);
            }
        }
        //判断最后是否为User，若是则删除。
        if (CollectionUtils.isNotEmpty(messages)) {
            if (LLMRoleEnum.USER.getRole().equals(messages.get(messages.size() - 1).getRole())) {
                Long recordId = recordEntities.get(recordEntities.size() - 1).getId();
                bizAgentApplicationDialoguesRecordService.deletedById(recordId);
                messages.remove(messages.size() - 1);
            }
        }

        // 用户输入
        Message message = new Message();
        message.setContent(input);
        message.setRole(LLMRoleEnum.USER.getRole());
        messages.add(message);
        return messages;
    }

    public MinerUOcrResult ocrPrase(File file) {
//        return minerUOcrService.fileParse(file);
        return new MinerUOcrResult();
    }

    public List<FileUploadDto> handleDuplicateFileNames(List<FileUploadDto> fileUploadDtoList) {
        Map<String, Integer> fileNameCountMap = new HashMap<>();

        return fileUploadDtoList.stream().map(dto -> {
            String originalFileName = dto.getFileName();
            int count = fileNameCountMap.getOrDefault(originalFileName, 0);
            fileNameCountMap.put(originalFileName, count + 1);

            if (count > 0) {
                String newFileName = originalFileName + "(" + count + ")";
                dto.setFileName(newFileName);
            }
            return dto;
        }).collect(Collectors.toList());
    }

}