package com.qingyun.service.compare.strategy;

import cn.hutool.core.util.IdUtil;
import com.github.difflib.patch.DeltaType;
import com.qingyun.common.config.QingYunConfig;
import com.qingyun.common.exception.ServiceException;
import com.qingyun.common.utils.DateUtils;
import com.qingyun.common.utils.StringUtils;
import com.qingyun.service.compare.BoundingBox;
import com.qingyun.service.compare.DiffRegion;
import com.qingyun.service.compare.PdfDiffWithPosition;
import com.qingyun.service.domain.ContractCompareResult;
import com.qingyun.service.domain.ContractCompareTask;
import com.qingyun.service.mapper.ContractCompareResultMapper;
import com.qingyun.service.mapper.ContractCompareTaskMapper;
import com.qingyun.service.utils.PdfUtil;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.pdfbox.Loader;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.junit.jupiter.api.Order;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.util.*;

@Component
@Order(3)
public class WordComparisonStrategy extends AbstractFileComparisonStrategy implements Ordered {

    @Autowired
    private PdfUtil pdfUtil;

    @Autowired
    private PdfDiffWithPosition pdfDiffWithPosition;

    @Autowired
    private ContractCompareResultMapper compareResultMapper;

    @Autowired
    private ContractCompareTaskMapper contractCompareTaskMapper;

    @Override
    protected void doExtract(ContractCompareTask task) {


        File firstFile = null;
        File secondFile = null;
        try {
            // 转换成pdf
            Pair<String, File> firstMap = processContractFile(task.getFirstContractUrl(), task.getFirstContractName());
            Pair<String, File> secondMap = processContractFile(task.getSecondContractUrl(), task.getSecondContractName());

            task.setFirstContractUrl(firstMap.getLeft());
            task.setSecondContractUrl(secondMap.getLeft());

            task.setFirstContractName(task.getFirstContractName().replaceAll("\\.(doc|docx)$", ".pdf"));
            task.setSecondContractName(task.getSecondContractName().replaceAll("\\.(doc|docx)$", ".pdf"));

            firstFile = firstMap.getRight();
            PDDocument firstDocument = Loader.loadPDF(firstFile);
            if (firstDocument == null) {
                throw new ServiceException("解析PDF文件失败");
            }
//            // 判断是否是扫描件pdf
//            if (PdfScanChecker.isScannedPdf(firstDocument)) {
//                // 扫描件pdf -> orc识别 -> 重组成新的文字pdf
//
//            }
            task.setFirstPageNum(firstDocument.getNumberOfPages());
            if (firstDocument.getNumberOfPages() > 0) {
                task.setFirstContractContent(firstDocument.getPage(0).getContents().toString());
                task.setFirstWidth(firstDocument.getPage(0).getMediaBox().getWidth());
                task.setFirstHeight(firstDocument.getPage(0).getMediaBox().getHeight());
            }
            secondFile = secondMap.getRight();
            PDDocument secondDocument = Loader.loadPDF(secondFile);
            if (secondDocument == null) {
                throw new ServiceException("解析PDF文件失败");
            }
            task.setSecondPageNum(secondDocument.getNumberOfPages());
            if (secondDocument.getNumberOfPages() > 0) {
                task.setSecondWidth(secondDocument.getPage(0).getMediaBox().getWidth());
                task.setSecondHeight(secondDocument.getPage(0).getMediaBox().getHeight());
            }
            firstDocument.close();
            secondDocument.close();

        } catch (Exception e) {
            log.error("解析PDF文件失败", e);
            updateTaskStatus(task, 4, "解析PDF文件失败");
            return;
        }
        updateTaskStatus(task, 2, "文本提取完成");
    }

    @Override
    protected List<DiffRegion> doCompare(ContractCompareTask task) {
        return pdfDiffWithPosition.compare(task);
    }

    @Override
    protected ContractCompareResult buildResult(ContractCompareTask task, DiffRegion change) {
        ContractCompareResult contractCompareResult = new ContractCompareResult();
        contractCompareResult.setTaskId(task.getTaskId());

        contractCompareResult.setBaseDiffContent(StringUtils.isNotBlank(change.getSourceText()) ? change.getSourceText() : "");
        contractCompareResult.setCompareDiffContent(StringUtils.isNotBlank(change.getTargetText()) ? change.getTargetText() : "");

        // 源文本的变动类型，要根据目标的变动类型来处理，change - change , delete - insert, insert - delete
        if (Objects.equals(change.getChangeType(), DeltaType.CHANGE.name())) {
            contractCompareResult.setBaseDiffType("change");
            contractCompareResult.setCompareDiffType("change");
        } else if (Objects.equals(change.getChangeType(), DeltaType.DELETE.name())) {
            contractCompareResult.setBaseDiffType("insert");
            contractCompareResult.setCompareDiffType("delete");
        } else if (Objects.equals(change.getChangeType(), DeltaType.INSERT.name())) {
            contractCompareResult.setBaseDiffType("delete");
            contractCompareResult.setCompareDiffType("insert");
        }

        if (change.getSourceBox() != null) {
            BoundingBox sourceBox = change.getSourceBox();
            contractCompareResult.setBaseBoxArea(
                sourceBox.getX() + "," + sourceBox.getY() + "," + sourceBox.getWidth() + "," + sourceBox.getHeight());

            contractCompareResult.setBasePageNum(change.getSourcePage());
        } else {
            // 没有源文本，则取目标文本的定位
            BoundingBox targetBox = change.getTargetBox();
            contractCompareResult.setBaseBoxArea(
                targetBox.getX() + "," + targetBox.getY() + "," + targetBox.getWidth() + "," + targetBox.getHeight());
            contractCompareResult.setBasePageNum(change.getTargetPage());
        }
        if (change.getTargetBox() != null) {
            BoundingBox targetBox = change.getTargetBox();
            contractCompareResult.setCompareBoxArea(
                targetBox.getX() + "," + targetBox.getY() + "," + targetBox.getWidth() + "," + targetBox.getHeight());
            contractCompareResult.setComparePageNum(change.getTargetPage());
        } else {
            // 没有目标文本，则取源文本的定位
            BoundingBox sourceBox = change.getSourceBox();
            contractCompareResult.setCompareBoxArea(
                sourceBox.getX() + "," + sourceBox.getY() + "," + sourceBox.getWidth() + "," + sourceBox.getHeight());
            contractCompareResult.setComparePageNum(change.getSourcePage());
        }
        contractCompareResult.setCreateTime(new Date());
        return contractCompareResult;
    }

    @Override
    protected void saveResults(List<ContractCompareResult> results) {
        compareResultMapper.insertBatch(results);
    }

    @Override
    protected void updateTaskStatus(ContractCompareTask task, int status, String msg) {
        task.setStatus(status);
        task.setErrorMsg(msg);
        contractCompareTaskMapper.updateById(task);
    }

    @Override
    public boolean supports(String fileExtension) {
        return "doc".equals(fileExtension) || "docx".equals(fileExtension);
    }

    @Override
    public int getOrder() {
        return 3;
    }

    /**
     * 处理上传的合同文件，如果上传的是Word文件则转换为PDF，并更新合同URL
     *
     * @return 处理后的PDF文件
     * @throws IOException IO异常
     * @throws ServiceException 服务异常
     */
    private Pair<String, File> processContractFile(String url, String fileName) throws IOException, ServiceException {
        File pdfFile;
        File tempFile = null;
        try {
            // 临时文件
            tempFile = pdfUtil.downloadFile(url, fileName);
            fileName = fileName.toLowerCase();

            // 判断文件类型
            // 如果是word类型转换成pdf
            pdfFile = pdfUtil.convertWordToPdf(tempFile);
            // 在用户上传的word文件路径目录下创建新的pdf格式文件路径
            String needUploadName = DateUtils.datePath() + "/" + IdUtil.fastUUID() + "/" +
                fileName.substring(0, fileName.lastIndexOf(".")) + ".pdf";
            String filePath = QingYunConfig.getUploadPath() + "/" + needUploadName;

            // 确保目录存在
            File destFile = new File(filePath);
            destFile.getParentFile().mkdirs();

            // 将转换后的PDF文件移动到目标位置
            File targetFile = new File(filePath);
            if (pdfFile.renameTo(targetFile)) {
                pdfFile = targetFile;
            } else {
                // 如果renameTo失败，尝试复制文件
                try (FileInputStream fis = new FileInputStream(pdfFile)) {
                    Files.copy(pdfFile.toPath(), targetFile.toPath());
                    pdfFile = targetFile;
                }
            }
            // 更新合同URL为新的PDF文件路径
            String newUrl = "/profile/upload/" + needUploadName;

            return Pair.of(newUrl, pdfFile);
        } catch (Exception e) {
            // 清理临时文件
            if (tempFile != null && tempFile.exists()) {
                Files.deleteIfExists(tempFile.toPath());
            }
            throw new ServiceException("处理文件失败: " + e.getMessage());
        } finally {
            if (tempFile != null) {
                Files.deleteIfExists(tempFile.toPath());
            }
        }
    }
}
