package cn.com.poc.ai_software_copyright.aggregate.impl;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;

import cn.com.gsst.dify_client.exception.DifyApiException;
import cn.com.poc.ai_software_copyright.agent.SoftwareCopyRightAgent;
import cn.com.poc.ai_software_copyright.aggregate.SoftwareCopyRightService;
import cn.com.poc.ai_software_copyright.contant.AiSoftWareCopyRightEnum;
import cn.com.poc.ai_software_copyright.convert.BizSoftwareCopyrightConvert;
import cn.com.poc.ai_software_copyright.domain.BaseInfo;
import cn.com.poc.ai_software_copyright.domain.TechnicalContent;
import cn.com.poc.ai_software_copyright.entity.BizSoftwareCopyrightDocRecordEntity;
import cn.com.poc.ai_software_copyright.entity.BizSoftwareCopyrightEntity;
import cn.com.poc.ai_software_copyright.entity.CallbackEntity;
import cn.com.poc.ai_software_copyright.query.SoftwareCopyrightQueryCondition;
import cn.com.poc.ai_software_copyright.query.SoftwareCopyrightQueryItem;
import cn.com.poc.ai_software_copyright.service.BizSoftwareCopyrightDocRecordService;
import cn.com.poc.ai_software_copyright.service.BizSoftwareCopyrightService;
import cn.com.poc.ai_software_copyright.utils.SoftwareCopyRightUtils;
import cn.com.poc.common.constant.CommonConstant;
import cn.com.poc.common.model.BizFileUploadRecordModel;
import cn.com.poc.common.service.BizFileUploadRecordService;
import cn.com.poc.common.service.BosConfigService;
import cn.com.poc.common.service.RedisService;
import cn.com.poc.common.utils.DocumentLoad;
import cn.com.poc.common.utils.FileUtils;
import cn.com.poc.common.utils.JsonUtils;
import cn.com.poc.common.utils.MD5Util;
import cn.com.poc.common.utils.StringUtils;
import cn.com.yict.framemax.core.exception.BusinessException;
import cn.com.yict.framemax.data.model.PagingInfo;
import cn.hutool.core.util.ZipUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

/**
 * 软著-聚合服务
 *
 * @author alex.yao
 * @date 2025/12/26
 */
@Service
public class SoftwareCopyRightServiceImpl implements SoftwareCopyRightService {

    private final Logger logger = LoggerFactory.getLogger(SoftwareCopyRightService.class);

    private final List<String> DRAFT_PENDING_RUNNING_STATUS = Arrays.asList(
            AiSoftWareCopyRightEnum.GENERATED_STATUS.Daft.name(),
            AiSoftWareCopyRightEnum.GENERATED_STATUS.Pending.name(),
            AiSoftWareCopyRightEnum.GENERATED_STATUS.Running.name()
    );

    @Resource
    private SoftwareCopyRightUtils softwareCopyRightUtils;

    @Resource
    private BosConfigService bosConfigService;

    @Resource
    private RedisService redisService;

    @Resource
    private BizFileUploadRecordService bizFileUploadRecordService;

    @Resource
    private SoftwareCopyRightAgent softwareCopyRightAgent;

    @Resource
    private BizSoftwareCopyrightService bizSoftwareCopyrightService;

    @Resource
    private BizSoftwareCopyrightDocRecordService bizSoftwareCopyrightDocRecordService;

    @Override
    public BizSoftwareCopyrightEntity save(BaseInfo baseInfo, TechnicalContent technicalContent,
                                           List<String> referenceDocumentFileUrl, List<String> generatedDocType) {
        BizSoftwareCopyrightEntity entity = new BizSoftwareCopyrightEntity();
        entity.setBaseInfo(JsonUtils.serialize(baseInfo));
        entity.setTechnicalContent(JsonUtils.serialize(technicalContent));
        if (CollectionUtils.isNotEmpty(referenceDocumentFileUrl)) {
            entity.setReferenceDocumentFileUrl(JsonUtils.serialize(referenceDocumentFileUrl));
        }
        entity.setGeneratedDocType(JsonUtils.serialize(generatedDocType));
        return bizSoftwareCopyrightService.save(entity);
    }

    @Override
    public void softwareCopyRightAssistant(
            AiSoftWareCopyRightEnum.AI_ASSISTANT_TYPE type,
            List<String> fileUrls,
            String question,
            Map<String, Object> data
    ) throws InterruptedException, DifyApiException, IOException {
        switch (type) {
            case MAIN_FUNCTION:
                question = "生成[软件的主要功能]";
                break;
            case TARGET_INDUSTRY:
                question = "生成[面向行业/领域]";
                break;
            case TECHNICAL_FEATURES:
                question = "生成[该软件的技术特点]";
                break;
            case DEVELOPMENT_PURPOSE:
                question = "生成[开发目的]";
                break;
            default:
                throw new BusinessException("不支持的AI助手类型: " + type);
        }
        fileUrls = softwareCopyRightUtils.downloadAndUnzipPlugin(fileUrls);
        softwareCopyRightAgent.softwareCopyRightAssistant(fileUrls, question, data);
    }

    @Override
    public TechnicalContent createTechnicalContent(List<String> fileUrls, BaseInfo baseInfo) throws IOException {
        Map<String, Object> data = new HashMap<>();
        List<File> tempFiles = new ArrayList<>(); // 用于跟踪临时文件

        try {
            // 下载文件内容
            if (CollectionUtils.isNotEmpty(fileUrls)) {
                StringBuilder stringBuilder = new StringBuilder();
                StringBuilder codeBuilder = new StringBuilder();

                for (String fileUrl : fileUrls) {
                    File file = DocumentLoad.downloadURLDocument(fileUrl);
                    tempFiles.add(file); // 添加到临时文件列表

                    // 判断是否为压缩文件并解压
                    if (FileUtils.isCompressedFile(file)) {
                        try {
                            //解压文件，获取解压后的文件列表
                            List<File> files = FileUtils.unGzip(file);
                            if (files != null) { // 添加空值检查
                                for (File codeFiles : files) {
                                    // 验证文件名安全性
                                    String fileName = FileUtils.sanitizeFileName(codeFiles.getName());
                                    String fileContent = DocumentLoad.documentToText(codeFiles);
                                    codeBuilder.append("##").append(fileName).append(StringUtils.LF);
                                    codeBuilder.append(fileContent).append(StringUtils.LF);

                                    // 添加到临时文件列表以便清理
                                    tempFiles.add(codeFiles);
                                }
                            }
                        } catch (Exception e) {
                            logger.error("解压文件失败: {}", file.getAbsolutePath(), e);
                            throw new IOException("解压文件失败: " + file.getAbsolutePath(), e);
                        }
                    } else {
                        try {
                            // 验证文件名安全性
                            String fileName = FileUtils.sanitizeFileName(file.getName());
                            String fileContent = DocumentLoad.documentToText(file);
                            stringBuilder.append("##").append(fileName).append(StringUtils.LF);
                            stringBuilder.append(fileContent).append(StringUtils.LF);
                        } catch (Exception e) {
                            logger.error("读取文件内容失败: {}", file.getAbsolutePath(), e);
                            throw new IOException("读取文件内容失败: " + file.getAbsolutePath(), e);
                        }
                    }
                }
                data.put("files", stringBuilder.toString());
                data.put("code", codeBuilder.toString());
            }

            String baseInfoStr = JsonUtils.serialize(baseInfo);
            String technicalContent = softwareCopyRightAgent.technicalContent(null, baseInfoStr, data);
            logger.info("【技术内容】 baseInfo:{},生成结果: {}", baseInfoStr, technicalContent);
            if (StringUtils.isBlank(technicalContent)) {
                throw new BusinessException("执行【技术内容】生成异常");
            }
            return JsonUtils.deSerialize(technicalContent, TechnicalContent.class);
        } finally {
            // 清理临时文件
            for (File tempFile : tempFiles) {
                if (tempFile != null && tempFile.exists()) {
                    try {
                        tempFile.delete();
                    } catch (Exception e) {
                        logger.warn("删除临时文件失败: {}", tempFile.getAbsolutePath(), e);
                    }
                }
            }
        }
    }


    @Override
    public BizSoftwareCopyrightDocRecordEntity listFile(Long id) {
        checkTaskIsComplete(id);
        BizSoftwareCopyrightDocRecordEntity bizSoftwareCopyrightDocRecordEntity =
                new BizSoftwareCopyrightDocRecordEntity();
        bizSoftwareCopyrightDocRecordEntity.setRelationId(id);
        bizSoftwareCopyrightDocRecordEntity.setIsDeleted(CommonConstant.IsDeleted.N);
        List<BizSoftwareCopyrightDocRecordEntity> recordEntities =
                bizSoftwareCopyrightDocRecordService.findByExample(bizSoftwareCopyrightDocRecordEntity, null);
        return recordEntities.get(0);
    }

    @Override
    public String getDownloadUrl(Long id) {
        checkTaskIsComplete(id);
        BizSoftwareCopyrightDocRecordEntity recordEntity = bizSoftwareCopyrightDocRecordService.getByRelationId(id);
        if (recordEntity == null) {
            throw new BusinessException("查询无记录");
        }
        if (StringUtils.isBlank(recordEntity.getAggregationUrl())) {
            zipFilesAndUpdateRecord(recordEntity);
        }
        return recordEntity.getAggregationUrl();
    }

    @Override
    public String upload(MultipartFile file) throws IOException {
        String md5 = MD5Util.fileToMD5(file.getInputStream());
        BizFileUploadRecordModel fileUploadRecordModel = bizFileUploadRecordService.getByMD5(md5);
        if (fileUploadRecordModel != null) {
            return fileUploadRecordModel.getFileUrl();
        }

        String contentType = file.getContentType();
        String originalFilename = file.getOriginalFilename();
        assert originalFilename != null;
        String prefix = originalFilename.substring(originalFilename.lastIndexOf(".")).replaceAll("\\.", "");
        String upload = bosConfigService.upload(file.getInputStream(), prefix, contentType);

        BizFileUploadRecordModel bizFileUploadRecordModel = new BizFileUploadRecordModel();
        bizFileUploadRecordModel.setFileName(file.getOriginalFilename());
        bizFileUploadRecordModel.setFileUrl(upload);
        bizFileUploadRecordModel.setMd5(md5);
        bizFileUploadRecordModel.setCoverSheetUrl("");
        bizFileUploadRecordService.save(bizFileUploadRecordModel);
        return upload;
    }

    @Override
    public void callbackGeneratedBaseDoc(String taskId, String type, CallbackEntity callbackEntity) {
        if (redisService.hasKey(taskId)) {
            if (type.equals("success")) {
                redisService.set(taskId, "success");
            } else if (type.equals("error")) {
                redisService.set(taskId, "error");
            } else {
                redisService.set(taskId + ":" + type, JsonUtils.serialize(callbackEntity));
            }
        } else {
            logger.error("-------------------任务不存在: {}---------------------", taskId);
            throw new BusinessException("任务不存在");
        }
    }

    @Override
    public List<BizSoftwareCopyrightEntity> querySoftwareCopyRight(String query, String generatedStatus,
                                                                   PagingInfo pagingInfo) {
        SoftwareCopyrightQueryCondition condition = new SoftwareCopyrightQueryCondition();
        if (StringUtils.isNotBlank(generatedStatus)) {
            if (DRAFT_PENDING_RUNNING_STATUS.contains(generatedStatus)) {
                condition.setGeneratedStatusList(DRAFT_PENDING_RUNNING_STATUS);
            } else {
                condition.setGeneratedStatus(generatedStatus);
            }
        }
        condition.setQuery(query);
        List<SoftwareCopyrightQueryItem> softwareCopyrightQueryItems =
                bizSoftwareCopyrightService.softwareCopyrightQuery(condition, pagingInfo);
        return softwareCopyrightQueryItems.stream()
                .map(BizSoftwareCopyrightConvert::softwareCopyrightQueryItemToEntity)
                .collect(Collectors.toList());
    }

    /**
     * 压缩文件并更新记录
     *
     * @param recordEntity
     * @return
     */
    private String zipFilesAndUpdateRecord(BizSoftwareCopyrightDocRecordEntity recordEntity) {
        String pcOperatingManualUrl = recordEntity.getPcOperatingManual();
        String informationUrl = recordEntity.getInformation();
        String phOperatingManualUrl = recordEntity.getPhOperatingManual();
        String sourceCodeUrl = recordEntity.getSourceCode();
        List<File> files = new CopyOnWriteArrayList<>();

        // 添加所有有效的文件URL到文件列表，使用异步并行下载
        CompletableFuture<Void> pcOperatingManualUrlFuture = CompletableFuture.runAsync(() -> {
            addFileIfNotBlank(pcOperatingManualUrl, files);
        }).exceptionally(throwable -> {
            logger.error("下载PC操作手册失败: {}", pcOperatingManualUrl, throwable);
            throw new BusinessException("下载PC操作手册失败");
        });

        CompletableFuture<Void> informationUrlFuture = CompletableFuture.runAsync(() -> {
            addFileIfNotBlank(informationUrl, files);
        }).exceptionally(throwable -> {
            logger.error("下载信息文件失败: {}", informationUrl, throwable);
            throw new BusinessException("下载信息文件失败");
        });

        CompletableFuture<Void> phOperatingManualUrlFuture = CompletableFuture.runAsync(() -> {
            addFileIfNotBlank(phOperatingManualUrl, files);
        }).exceptionally(throwable -> {
            logger.error("下载手机操作手册失败: {}", phOperatingManualUrl, throwable);
            throw new BusinessException("下载手机操作手册失败");
        });

        CompletableFuture<Void> sourceCodeUrlFuture = CompletableFuture.runAsync(() -> {
            addFileIfNotBlank(sourceCodeUrl, files);
        }).exceptionally(throwable -> {
            logger.error("下载源码失败: {}", sourceCodeUrl, throwable);
            throw new BusinessException("下载源码失败");
        });

        // 等待所有文件下载完成后再执行压缩和上传
        try {
            CompletableFuture.allOf(pcOperatingManualUrlFuture, informationUrlFuture,
                    phOperatingManualUrlFuture, sourceCodeUrlFuture).join();
        } catch (CompletionException e) {
            logger.error("文件下载过程中发生错误:{}", e.getMessage());
            throw new BusinessException("文件下载过程中发生错误");
        }

        if (CollectionUtils.isEmpty(files)) {
            throw new BusinessException("文档下载失败");
        }

        File zipFile = null;
        try {
            // 创建临时文件用于存放压缩包，对文件名进行安全处理
            String safeFileName = FileUtils.sanitizeFileName(String.valueOf(recordEntity.getId()));
            zipFile = File.createTempFile("aggregation_" + safeFileName, ".zip");
            // 将所有文件打包成zip
            ZipUtil.zip(zipFile, Charset.defaultCharset(), false, files.toArray(new File[0]));

            // 使用try-with-resources确保流被正确关闭
            try (InputStream zipInputStream = Files.newInputStream(zipFile.toPath())) {
                // 上传压缩包到BOS并获取URL
                String aggregationUrl = bosConfigService.upload(zipInputStream, "zip",
                        "application/zip");
                // 更新数据库中的聚合URL
                recordEntity.setAggregationUrl(aggregationUrl);
                bizSoftwareCopyrightDocRecordService.update(recordEntity);
                return aggregationUrl;
            }
        } catch (IOException e) {
            throw new BusinessException("压缩包创建或上传失败", e);
        } catch (Exception e) {
            throw new BusinessException("压缩包处理失败", e);
        } finally {
            // 清理临时文件
            files.forEach(file -> {
                try {
                    Files.deleteIfExists(file.toPath());
                } catch (IOException e) {
                    logger.error("删除临时文件失败: {}", file.getAbsolutePath(), e);
                }
            });

            if (zipFile != null && zipFile.exists()) {
                try {
                    Files.deleteIfExists(zipFile.toPath());
                } catch (IOException e) {
                    logger.error("删除临时压缩文件失败: {}", zipFile.getAbsolutePath(), e);
                }
            }
        }
    }


    /**
     * 如果URL不为空白，则下载文件并添加到文件列表
     *
     * @param fileUrl 文件URL
     * @param files   文件列表
     */
    private void addFileIfNotBlank(String fileUrl, List<File> files) {
        if (StringUtils.isNotBlank(fileUrl)) {
            File file = DocumentLoad.downloadURLDocument(fileUrl);
            files.add(file);
        }
    }

    private void checkTaskIsComplete(Long id) {
        BizSoftwareCopyrightEntity bizSoftwareCopyrightEntity = bizSoftwareCopyrightService.get(id);
        if (bizSoftwareCopyrightEntity == null) {
            throw new BusinessException("查询任务失败");
        }
        String generatedStatus = bizSoftwareCopyrightEntity.getGeneratedStatus();
        if (!generatedStatus.equals(AiSoftWareCopyRightEnum.GENERATED_STATUS.Complete.name())) {
            throw new BusinessException("任务未完成");
        }
    }

}