package com.yaoyicloud.service.impl;

import static com.yaoyicloud.config.SessionInterceptor.SESSION_MAP;

import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import com.amazonaws.services.s3.model.S3Object;
import com.amazonaws.services.s3.model.S3ObjectInputStream;
import com.yaoyicloud.config.RelationCounterRedisUtil;
import com.yaoyicloud.easier.common.file.core.FileProperties;
import com.yaoyicloud.easier.common.file.core.FileTemplate;
import com.yaoyicloud.render.cso.EntAppendixRender;
import com.yaoyicloud.render.cso.EntProductIntroductionRender;
import com.yaoyicloud.render.cso.EntPromotionDetailsRender;
import com.yaoyicloud.tools.CsoOfficeUtil;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.springframework.stereotype.Service;
import com.yaoyicloud.config.CommonDataCache;
import com.yaoyicloud.config.FilerepoProperties;
import com.yaoyicloud.config.ReportPathManager;
import com.yaoyicloud.constant.enums.ModuleType;
import com.yaoyicloud.entity.ReportGenerationResult;
import com.yaoyicloud.render.cso.EntHeaderSectionRender;
import com.yaoyicloud.render.cso.EntPromotionSummaryRender;
import com.yaoyicloud.service.CsoReportService;
import com.yaoyicloud.tools.OfficeUtil;
import com.yaoyicloud.tools.DocxUtil;

import cn.hutool.core.util.IdUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.util.Arrays;

@Slf4j
@Service
@RequiredArgsConstructor
public class CsoReportServiceImpl implements CsoReportService {
    private final FilerepoProperties filerepoProperties;
    private final ReportPathManager reportPathManager;
    private final CommonDataCache commonDataCache;
    private final FileTemplate ossTemplate;
    private final FileProperties properties;
    private final RelationCounterRedisUtil relationCounterRedisUtil;
    private final FileProperties fileProperties;

    /**
     * 处理单个模块的报告生成
     */
    @SuppressWarnings("checkstyle:ParameterNumber")
    private String processModule(ModuleType moduleType, String data,
        InputStream inputStream, String sessionId, Long relationId, Integer counter) throws Exception {
        String reportPath;
        String type = moduleType.getType();
        switch (moduleType) {
            case CSO_HEADER_XINHUA:
            case CSO_HEADER:
                reportPath = new EntHeaderSectionRender(sessionId, ossTemplate, fileProperties, filerepoProperties,
                    commonDataCache)
                        .createCSODocument(data, inputStream, String.valueOf(relationId), counter, type);
                break;
            case CSO_PRODUCT_INTRODUCTION_XINHUA:
            case CSO_PRODUCT_INTRODUCTION:
                reportPath = new EntProductIntroductionRender(sessionId, ossTemplate, fileProperties,
                    filerepoProperties, commonDataCache)
                        .createCSODocument(data, inputStream, String.valueOf(relationId), counter, type);
                break;
            case CSO_PROMOTION_SUMMARY:
                reportPath = new EntPromotionSummaryRender(sessionId, ossTemplate, fileProperties, filerepoProperties,
                    commonDataCache)
                        .createCSODocument(data, inputStream, String.valueOf(relationId), counter, type);
                break;
            case CSO_ATTACHMENT_XINHUA:
            case CSO_PROMOTION_DETAILS_XINHUA:
            case CSO_PROMOTION_DETAILS_1611890606:
            case CSO_PROMOTION_DETAILS:
                reportPath = new EntPromotionDetailsRender(sessionId, ossTemplate, fileProperties, filerepoProperties,
                    commonDataCache)
                        .createCSODocument(data, inputStream, String.valueOf(relationId), counter, type);
                break;

            case CSO_SITUATION_OVERVIEW_XINHUA:
            case CSO_PROMOTION_SIGNIFICANCE_XINHUA:
            case CSO_PROMOTION_SIGNIFICANCE_DRUG:
            case CSO_SITUATION_OVERVIEW_DRUG:
            case CSO_APPENDIX:
                reportPath =
                    new EntAppendixRender(sessionId, ossTemplate, fileProperties, filerepoProperties, commonDataCache)
                        .createCSODocument(data, inputStream, String.valueOf(relationId), counter, type);
                break;
            default:
                throw new UnsupportedOperationException("Unsupported module type: " + moduleType);
        }
        return reportPath;
    }

    @Override
    public ReportGenerationResult createCsoCheckReport(String data, Long relationId,
        ModuleType moduleType, Boolean mergeflag) throws Exception {
        // oss 获取文件
        String sessionId = SESSION_MAP.get(relationId.toString());
        String reportPath;
        String mergedReportPath = null;
        try {
            S3Object s3Object = ossTemplate.getObject(properties.getBucketName(), moduleType.getType() + ".docx");
            S3ObjectInputStream objectContent = s3Object.getObjectContent();

            Integer count = relationCounterRedisUtil.getCount(relationId);

            reportPath = processModule(moduleType, data, objectContent, sessionId, relationId, count);
            // 处理指定模块
            reportPathManager.addReportPath(sessionId, reportPath);
            relationCounterRedisUtil.increment(relationId, 1);

            if (mergeflag) {
                List<String> reportPaths = reportPathManager.removeSession(sessionId);
                XWPFDocument targetDoc;
                try (FileInputStream fis = new FileInputStream(reportPaths.get(0))) {
                    targetDoc = new XWPFDocument(fis);
                }
                List<XWPFDocument> sourceDocs = new ArrayList<>();
                for (int i = 1; i < reportPaths.size(); i++) {
                    try (FileInputStream fis = new FileInputStream(reportPaths.get(i))) {
                        sourceDocs.add(new XWPFDocument(fis));
                    }
                }
                String label = relationId + "_" + IdUtil.fastSimpleUUID();
                mergedReportPath = filerepoProperties.getBasePath() + "/" + label + ".docx";
                // 调用合并方法
                DocxUtil.mergeDocx(targetDoc, sourceDocs, mergedReportPath, relationId);
            }
        } catch (Exception e) {
            log.error("生成CSO报告失败，开始清除相关缓存", e);

            if (relationId != null) {
                relationCounterRedisUtil.reset(relationId); // 清除计数缓存
            }
            if (sessionId != null) {
                reportPathManager.removeSession(sessionId); // 清除会话对应的报告路径
                SESSION_MAP.remove(relationId.toString()); // 清除会话映射
            }
            // 重新抛出异常，不影响上层处理
            throw e;
        }

        return new ReportGenerationResult(reportPath, mergedReportPath, mergeflag);
    }

    @Override
    public ByteArrayOutputStream saveToTempFile(byte[] fileBytes) {
        // 1. 初始化路径和字体配置
        String imagePath = filerepoProperties.getReportImagePath();
        List<String> fontLists = Arrays.asList(filerepoProperties.getSourceHanSansCnFontMediumPath());
        // 2. 创建临时Word文件（自动清理）
        File reportTempWordFile = null;
        try {
            reportTempWordFile = File.createTempFile("temp_word_", ".docx");
            Files.write(reportTempWordFile.toPath(), fileBytes);

            String html = OfficeUtil.convert(reportTempWordFile.getAbsolutePath(), imagePath);
            try (BufferedWriter writer2 = new BufferedWriter(new FileWriter("1.html"))) {
                writer2.write(html);
            } catch (IOException e) {
                System.err.println("写入 1.html 文件时发生错误: " + e.getMessage());
                e.printStackTrace();
            }
            String html1 = CsoOfficeUtil.formatHtmlCso(html);
            try (BufferedWriter writer2 = new BufferedWriter(new FileWriter("2.html"))) {
                writer2.write(html1);
            } catch (IOException e) {
                System.err.println("写入 2.html 文件时发生错误: " + e.getMessage());
                e.printStackTrace();
            }
            CsoOfficeUtil.convertHtmlToPdfCso(html1, fontLists, imagePath, true);
            String html2 = OfficeUtil.formatHtml(html);

            try (BufferedWriter writer2 = new BufferedWriter(new FileWriter("3.html"))) {
                writer2.write(html2);
            } catch (IOException e) {
                System.err.println("写入 3.html 文件时发生错误: " + e.getMessage());
                e.printStackTrace();
            }
            return CsoOfficeUtil.convertHtmlToPdfCso(html2, fontLists, imagePath, false);
        } catch (Exception e) {
            log.error("文件转换失败", e);
            return null;
        }
    }

    private void quietlyDelete(File file) {
        if (file != null && file.exists()) {
            try {
                Files.delete(file.toPath());
            } catch (IOException e) {
                log.warn("无法删除临时文件 {}: {}", file.getAbsolutePath(), e.getMessage());
            }
        }
    }

}
