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.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CopyOnWriteArrayList;

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.domian.BaseInfo;
import cn.com.poc.ai_software_copyright.domian.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.service.BizSoftwareCopyrightDocRecordService;
import cn.com.poc.ai_software_copyright.service.BizSoftwareCopyrightService;
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.utils.DocumentLoad;
import cn.com.poc.common.utils.JsonUtils;
import cn.com.poc.common.utils.StringUtils;
import cn.com.yict.framemax.core.exception.BusinessException;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ZipUtil;
import cn.hutool.crypto.digest.MD5;
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);

    @Resource
    private BosConfigService bosConfigService;

    @Resource
    private BizFileUploadRecordService bizFileUploadRecordService;

    @Resource
    private SoftwareCopyRightAgent softwareCopyRightAgent;

    @Resource
    private BizSoftwareCopyrightService bizSoftwareCopyrightService;

    @Resource
    private BizSoftwareCopyrightDocRecordService bizSoftwareCopyrightDocRecordService;


    @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:
                softwareCopyRightAgent.mainFunction(fileUrls, "生成[开发目的]", data);
                break;
            case TARGET_INDUSTRY:
                softwareCopyRightAgent.targetIndustry(fileUrls, "生成[面向行业/领域]", data);
                break;
            case TECHNICAL_FEATURES:
                softwareCopyRightAgent.technicalFeatures(fileUrls, "生成[软件的主要功能]", data);
                break;
            case DEVELOPMENT_PURPOSE:
                softwareCopyRightAgent.developmentPurpose(fileUrls, "生成[技术特点]", data);
                break;
            default:
                throw new BusinessException("不支持的AI助手类型: " + type);
        }
    }

    @Override
    public TechnicalContent createTechnicalContent(List<String> fileUrls, BaseInfo baseInfo) throws IOException {
        Map<String, Object> data = new HashMap<>();
        // 下载文件内容
        if (CollectionUtils.isNotEmpty(fileUrls)) {
            StringBuilder stringBuilder = new StringBuilder();
            StringBuilder codeBuilder = new StringBuilder();
            for (String fileUrl : fileUrls) {
                File file = DocumentLoad.downloadURLDocument(fileUrl);

                // 判断是否为压缩文件并解压
                if (isCompressedFile(file)) {
                    //todo 解压文件，获取解压后的文件列表
                    List<File> files = unGzip(file);
                    for (File codeFiles : files) {
//                        String fileContent = DocumentLoad.documentToText(codeFiles);
//                        codeBuilder.append("##").append(file.getName()).append(StringUtils.LF);
//                        codeBuilder.append(fileContent).append(StringUtils.LF);
                    }

                } else {
                    String fileContent = DocumentLoad.documentToText(file);
                    stringBuilder.append("##").append(file.getName()).append(StringUtils.LF);
                    stringBuilder.append(fileContent).append(StringUtils.LF);
                }
            }
            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);
    }

    /**
     * 判断文件是否为压缩文件
     *
     * @param file 文件
     * @return 是否为压缩文件
     */
    private boolean isCompressedFile(File file) {
        String fileName = file.getName().toLowerCase();
        return fileName.endsWith(".zip") || fileName.endsWith(".tar") ||
                fileName.endsWith(".tar.gz") || fileName.endsWith(".tgz") ||
                fileName.endsWith(".rar") || fileName.endsWith(".7z");
    }

    /**
     * 解压文件
     *
     * @param gzipFile
     * @return
     * @throws IOException
     */
    private List<File> unGzip(File gzipFile) throws IOException {
        // 目标解压目录
        String destDir = Files.createTempDirectory("gzip/temp/").toString();
        // 确保目标目录存在
        FileUtil.mkdir(destDir);
        File[] extractedFiles = ZipUtil.unzip(gzipFile, new File(destDir)).listFiles();
        return ListUtil.toList(extractedFiles);
    }


    @Override
    public BizSoftwareCopyrightDocRecordEntity listFile(Long id) throws Exception {
        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) throws Exception {
        checkTaskIsComplete(id);
        BizSoftwareCopyrightDocRecordEntity bizSoftwareCopyrightDocRecordEntity =
                new BizSoftwareCopyrightDocRecordEntity();
        bizSoftwareCopyrightDocRecordEntity.setRelationId(id);
        bizSoftwareCopyrightDocRecordEntity.setIsDeleted(CommonConstant.IsDeleted.N);
        List<BizSoftwareCopyrightDocRecordEntity> recordEntities =
                bizSoftwareCopyrightDocRecordService.findByExample(bizSoftwareCopyrightDocRecordEntity, null);
        if (CollectionUtils.isEmpty(recordEntities)) {
            throw new BusinessException("查询无记录");
        }
        BizSoftwareCopyrightDocRecordEntity recordEntity = recordEntities.get(0);
        if (StringUtils.isBlank(recordEntity.getAggregationUrl())) {
            zipFilesAndUpdateRecord(recordEntity);
        }
        return recordEntity.getAggregationUrl();
    }


    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("任务未完成");
        }
    }

    @Override
    public String upload(MultipartFile file) throws IOException {
        String contentType = file.getContentType();
        String originalFilename = file.getOriginalFilename();
        String prefix = originalFilename.substring(originalFilename.lastIndexOf(".")).replaceAll("\\.", "");

        String upload = bosConfigService.upload(file.getInputStream(), prefix, contentType);

        //计算文件MD5值
        InputStream inputStream = file.getInputStream();
        byte[] bytes = new byte[inputStream.available()];
        inputStream.read(bytes);
        String md5 = MD5.create().digestHex(bytes);

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


    public 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);
        });
        CompletableFuture<Void> informationUrlFuture = CompletableFuture.runAsync(() -> {
            addFileIfNotBlank(informationUrl, files);
        });
        CompletableFuture<Void> phOperatingManualUrlFuture = CompletableFuture.runAsync(() -> {
            addFileIfNotBlank(phOperatingManualUrl, files);
        });
        CompletableFuture<Void> sourceCodeUrlFuture = CompletableFuture.runAsync(() -> {
            addFileIfNotBlank(sourceCodeUrl, files);
        });

        // 等待所有文件下载完成后再执行压缩和上传
        CompletableFuture.allOf(pcOperatingManualUrlFuture, informationUrlFuture,
                phOperatingManualUrlFuture, sourceCodeUrlFuture).join();

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

        File zipFile = null;
        try {
            // 创建临时文件用于存放压缩包
            zipFile = File.createTempFile("aggregation_" + recordEntity.getId(), ".zip");
            // 将所有文件打包成zip
            ZipUtil.zip(zipFile, Charset.defaultCharset(), false, files.toArray(new File[0]));
            // 上传压缩包到BOS并获取URL
            String aggregationUrl = bosConfigService.upload(Files.newInputStream(zipFile.toPath()), "zip",
                    "application/zip");
            // 更新数据库中的聚合URL
            recordEntity.setAggregationUrl(aggregationUrl);
            bizSoftwareCopyrightDocRecordService.update(recordEntity);
            return aggregationUrl;
        } 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);
        }
    }
}