package com.jwipc.finance.logic.impl;

import cn.hutool.core.io.resource.ResourceUtil;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.itextpdf.html2pdf.ConverterProperties;
import com.itextpdf.html2pdf.HtmlConverter;
import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.events.Event;
import com.itextpdf.kernel.events.IEventHandler;
import com.itextpdf.kernel.events.PdfDocumentEvent;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.kernel.pdf.extgstate.PdfExtGState;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Image;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.font.FontProvider;
import com.itextpdf.layout.properties.TextAlignment;
import com.itextpdf.layout.properties.UnitValue;
import com.jwipc.api.dto.ESignFileResposeDTO;
import com.jwipc.api.esign.SignFileCreateCallBackLogic;
import com.jwipc.constant.SignProcessType;
import com.jwipc.finance.logic.AccountStatementLogic;
import com.jwipc.prop.SysProp;
import com.jwipc.sys.client.ESignClient;
import com.jwipc.sys.client.FileClient;
import freemarker.template.Configuration;
import freemarker.template.Template;
import lombok.AllArgsConstructor;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.io.*;
import java.net.MalformedURLException;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 *
 */
@Service("PurchaseSaleSignFileCreateCallBack")
@RequiredArgsConstructor
public class PurchaseSaleSignFileCreateCallBack implements SignFileCreateCallBackLogic {

    private final AccountStatementLogic accountStatementLogic;
    private final Configuration freemarkerConfig;
    private final FileClient fileClient;
    private final ESignClient eSignClient;
    private final SysProp sysProp;

    /**
     * sign 回调接口
     *
     * @param businessId
     * @return
     */

    @Override
    public List<ESignFileResposeDTO> processor(Long businessId,Integer templateType) {
        // 对账单明细id
        Map<String, Object> map = accountStatementLogic.printPurchaseSale(businessId,templateType);
        map.put("ctx", sysProp.getHostUrl());
        Template template = null;

        String configValue = ResourceUtil.readUtf8Str("view/pc/finance/statement/purchase_sale_pdf.ftl");

        if (templateType!=null&&templateType == 1){
            configValue = ResourceUtil.readUtf8Str("view/pc/finance/statement/purchase_sale_pdf1.ftl");
        }
        try {
            // 生成html字符串
            template = new Template("emailTemplate", configValue, freemarkerConfig);
            String imgUrl = sysProp.getHostUrl() + "/static/img/invoice/gxhtlogo.png"; // gxlogo.png
            byte[] byteArray = convertToPdf(template, map, imgUrl);
            File file = fileClient.createFile("生成购销合同-" + IdWorker.getId() + ".pdf");
            // 通过FileChannel和FileLock来确保文件流不被占用
            try (FileOutputStream fos = new FileOutputStream(file);
                 FileChannel channel = fos.getChannel()) {
                // 尝试获得文件锁，避免其他进程或线程占用文件
                FileLock lock = channel.lock();
                try {
                    fos.write(byteArray);
                } finally {
                    // 解锁
                    lock.release();
                }
            }
            // 延迟等待文件释放，避免文件占用冲突
            waitForFileRelease(file);
            // 再次打开文件并进行处理
            File newFile = new File(file.getParent(), file.getName());
            // 使用 PdfReader 和 PdfWriter 进行处理
            PdfReader reader = new PdfReader(newFile);
            File tempFile = File.createTempFile("生成购销合同-" , ".pdf");
            int numberOfPages = 0;
            PdfWriter writer = new PdfWriter(tempFile);
            try (PdfDocument pdfDoc = new PdfDocument(reader, writer)) {
                numberOfPages = pdfDoc.getNumberOfPages();
                for (int i = 1; i <= numberOfPages; i++) {
                    String footerText = "　　　　　　　　　　　　　　　　　　　　　　　第" + i + "页 共" + numberOfPages  + "页";
                    PdfPage page = pdfDoc.getPage(i);
                    PdfCanvas canvas = new PdfCanvas(page);
                    try {
                        PdfExtGState extGState = new PdfExtGState();
                        extGState.setFillOpacity(1f); // 设置填充透明度为0.05
                        double alpha = Math.toRadians(0); // 倾斜角度
                        double tanAlpha = Math.tan(alpha);
                        //可根据页面宽高设置水印
                        canvas.saveState()
                                .concatMatrix(1, tanAlpha, 0, 1, 0, 0)
                                .beginText()
                                .resetFillColorGray()
                                .setExtGState(extGState)
                                .moveText(35, 40)
                                //.setFontAndSize(PdfFontFactory.createFont("/static/font/simsun.ttf", "Identity-H"), 10)
                                .setFontAndSize(PdfFontFactory.createFont("/static/font/msyh.ttc,1", "Identity-H"), 10)

                                .showText(footerText)
                                .endText()
                                .restoreState();
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }
            }

            // 上传到e签宝
            ESignFileResposeDTO eSignFileResposeDTO = fileClient.uploadESignFile(tempFile);
            String fileKey = eSignClient.sendFileClient(eSignFileResposeDTO, fileClient.file2MultipartFile(tempFile));
            // 插入fileKey
            eSignFileResposeDTO.setFileKey(fileKey);
            //返回文件总页数到前端，校验骑缝章的问题。 邓京术 2025-07-09
            eSignFileResposeDTO.setNumberOfPages(numberOfPages);
            List<ESignFileResposeDTO> eSignFileResposeDTOS = new ArrayList<>();
            eSignFileResposeDTOS.add(eSignFileResposeDTO);
            return eSignFileResposeDTOS;

        } catch (Exception e) {
            throw new RuntimeException("Error processing PDF file", e);
        }
    }

    /**
     * 当前服务是属于哪个流程1
     *
     * @return
     */
    @Override
    public SignProcessType getProcessType() {
        return SignProcessType.PURCHASE_SALE;
    }


    /**
     * 等待文件释放，直到文件不再被占用为止
     */
    private void waitForFileRelease(File file) {
        long startTime = System.currentTimeMillis();
        boolean isFileLocked = true;

        while (isFileLocked) {
            try {
                // 尝试通过读取文件的方式判断文件是否释放
                FileChannel fileChannel = new RandomAccessFile(file, "rw").getChannel();
                try {
                    // 如果获取文件锁成功，说明文件已经释放
                    FileLock lock = fileChannel.tryLock();
                    if (lock != null) {
                        lock.release();
                        isFileLocked = false;
                    }
                } finally {
                    fileChannel.close();
                }
            } catch (IOException e) {
                // 如果文件被占用，捕获异常并继续等待
                isFileLocked = true;
            }

            // 防止过度轮询，避免 CPU 高负载，等待一段时间再重试
            if (System.currentTimeMillis() - startTime > 30000) {
                // 如果超过30秒仍未释放文件，抛出超时异常
                throw new RuntimeException("File release timed out after 30 seconds: " + file.getName());
            }

            try {
                // 等待500毫秒后再次检查
                TimeUnit.MILLISECONDS.sleep(500);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                throw new RuntimeException("Thread interrupted while waiting for file release", e);
            }
        }
    }

    /**
     * 模板填充数据并转为PDF
     * @param template 模板名称
     * @param datas 填充的数据
     * @return
     */
    public static byte[] convertToPdf(Template template, Map<String, Object> datas,String imgUrl) {
        try {
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

            // 使用iText生成PDF
            PdfWriter writer = new PdfWriter(outputStream);
            PdfDocument pdf = new PdfDocument(writer);
            //"C:\\Users\\zwzn1755\\Desktop\\图片1.png")
            Image headerImage = new Image(ImageDataFactory.create(imgUrl));
            headerImage.setWidth(UnitValue.createPercentValue(100));
            // 页眉
            pdf.addEventHandler(PdfDocumentEvent.END_PAGE, new Header(imgUrl));
            // 页脚
            //     pdf.addEventHandler(PdfDocumentEvent.END_PAGE, new Footer(pdf));
            // PDF尺寸
            PageSize a4 = PageSize.A4;
            pdf.setDefaultPageSize(new PageSize(a4.getWidth(), a4.getHeight() - 20));

            // 处理模板并生成内容
            StringWriter htmlWriter = new StringWriter();
            template.process(datas, htmlWriter);
            String html = htmlWriter.toString();

            // PDF转换参数
            ConverterProperties converterProperties = new ConverterProperties();
            FontProvider fontProvider = new FontProvider();
            fontProvider.addFont(PdfFontFactory.createFont("/static/font/msyh.ttc,1", "Identity-H").getFontProgram(), "Identity-H");
            // PDF中需要显示加粗的字体：微软雅黑粗体
            converterProperties.setFontProvider(fontProvider);
            HtmlConverter.convertToPdf(html, pdf, converterProperties);
            return outputStream.toByteArray();

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 页眉
     */
    @AllArgsConstructor
    static class Header implements IEventHandler {
        private final String text;

        @Override
        public void handleEvent(Event event) {
            PdfDocumentEvent docEvent = (PdfDocumentEvent) event;
            PdfPage page = docEvent.getPage();
            PdfDocument document = docEvent.getDocument();
            Document document1 = new Document(document);

            try {
                Image logo = new Image(ImageDataFactory.create(text));
                logo.scaleToFit(100, 50); // 设置logo大小
                logo.setFixedPosition(36, document.getDefaultPageSize().getHeight() - 60); // 设置logo位置
                // 添加logo到文档
                document1.add(logo);
                // 添加文本 JWIPC Technology Co.,Ltd.
                String textContent = "JWIPC Technology Co.,Ltd."; // 要添加的文本内容
                // 添加文本
                float textRightMargin = 50; // 右边距
                Paragraph paragraph = new Paragraph(textContent)
                        .setFontSize(12) // 设置字体大小
                        .setFixedPosition(document.getDefaultPageSize().getWidth() - 150 - textRightMargin, document.getDefaultPageSize().getHeight() - 60, 150) // 设置文本位置
                        .setTextAlignment(TextAlignment.RIGHT); // 设置文本右对齐
                document1.add(paragraph);
                PdfCanvas pdfCanvas = new PdfCanvas(page);
                float x1 = 36; // 起始点X
                float y = document.getDefaultPageSize().getHeight() - 65; // 横线Y位置
                float x2 = document.getDefaultPageSize().getWidth() - 36; // 结束点X
                pdfCanvas.setLineWidth(1); // 设置线宽
                pdfCanvas.moveTo(x1, y); // 起点
                pdfCanvas.lineTo(x2, y); // 终点
                pdfCanvas.stroke(); // 绘制横线
            } catch (MalformedURLException e) {
                throw new RuntimeException(e);
            }
        }
    }



    /**
     * 页脚儿
     */
    static class Footer implements IEventHandler {
        private final PdfDocument pdfDocument;

        Footer(PdfDocument pdfDocument) {
            this.pdfDocument = pdfDocument;
        }

        @Override
        public void handleEvent(Event event) {
            PdfDocumentEvent docEvent = (PdfDocumentEvent) event;
            PdfPage page = docEvent.getPage();
            int currentPageNumber = pdfDocument.getPageNumber(page);
            int totalPageCount = pdfDocument.getNumberOfPages(); // Correctly fetch total page count
            System.out.println(docEvent.getDocument().getLastPage().getAnnotsSize());
            String footerText = "　　　　　　　　　　　　　　　　　　　　　　　第" + currentPageNumber + "页 共" + totalPageCount  + "页";

            PdfCanvas canvas = new PdfCanvas(page.newContentStreamBefore(), page.getResources(), pdfDocument);
            try {
                PdfExtGState extGState = new PdfExtGState();
                extGState.setFillOpacity(1f); // 设置填充透明度为0.05
                double alpha = Math.toRadians(0); // 倾斜角度
                double tanAlpha = Math.tan(alpha);
                //可根据页面宽高设置水印
                canvas.saveState()
                        .concatMatrix(1, tanAlpha, 0, 1, 0, 0)
                        .beginText()
                        .resetFillColorGray()
                        .setExtGState(extGState)
                        .moveText(35, 40)
                        //.setFontAndSize(PdfFontFactory.createFont("/static/font/simsun.ttf", "Identity-H"), 10)
                        .setFontAndSize(PdfFontFactory.createFont("/static/font/msyh.ttc,1", "Identity-H"), 10)

                        .showText(footerText)
                        .endText()
                        .restoreState();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
}
