package com.zehong.common.utils.poi;

import cn.afterturn.easypoi.word.WordExportUtil;
import cn.afterturn.easypoi.word.entity.MyXWPFDocument;
import cn.hutool.core.img.ImgUtil;
import com.zehong.common.config.ProjectNameConfig;
import com.zehong.common.exception.CustomException;
import com.zehong.common.utils.StringUtils;
import org.apache.poi.ss.usermodel.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URL;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * 安检单导出工具类
 */
public class InspectExportUtil {

    private static Logger logger = LoggerFactory.getLogger(InspectExportUtil.class);

    private List<String> fileNameList = new Vector<>();

    /**
     * 导出excel
     * @param template 导出模版
     * @param listData 数据
     */
    public String exportExcel(String template, List<Map<String,Object>> listData){
        logger.info("=========excel导出开始===========");
        ExecutorService executor = Executors.newFixedThreadPool(30);
        long exportStart = System.currentTimeMillis();
        for(Map map : listData){
            executor.submit(() ->{
                try {
                    createTable(template,map);
                } catch (Exception e) {
                    map.remove("exportLog");
                    logger.error("安检表导出失败" + e);
                    //throw new CustomException("安检导出失败" + e);
                }
            });
        }
        executor.shutdown();
        try {
            executor.awaitTermination(10, TimeUnit.MINUTES);
        } catch (InterruptedException e) {
            logger.error("线程出错:" + e);
        }
        long exportEnd = System.currentTimeMillis();
        logger.info("导出时间=============" + (exportEnd - exportStart));
        return fileNameList.isEmpty() ? "" : fileNameList.stream().collect(Collectors.joining(","));

    }

    /**
     * 导出word
     * @param template 模版名称
     * @param mapList 数据
     */
    public void exportEasyWord(String template,List<Map<String,Object>> mapList){
        logger.info("===========word导出开始==============");
        long start = System.currentTimeMillis();
        for(Map map : mapList){
            try {
                InputStream source = this.getClass().getResourceAsStream("/excelTemplate/" + template);
                MyXWPFDocument doc = new MyXWPFDocument(source);
                WordExportUtil.exportWord07(doc,map);
                String company = (String) map.get("company");
                String filename = (StringUtils.isNotEmpty(company) ? company : (String) map.get("username")) + map.get("createTime") + "安检单.docx";
                FileOutputStream out = new FileOutputStream(getExportAbsoluteFile(filename));
                doc.write(out);
                out.flush();
                out.close();
            } catch (Exception e) {
                map.remove("exportLog");
                logger.error("word安检单导出失败:" + e);
            }
        }
        long end = System.currentTimeMillis();
        logger.info("导出时间=============" + (end - start));

    }

    /**
     * 安检单压缩包导出
     * @param fileNameList 导出excel
     * @param zipName 压缩包名称
     * @return
     */
    public String zipExport(List<String> fileNameList,String zipName){
        long zipStart = System.currentTimeMillis();
        try{
            String fileName = zipName + ".zip";
            FileOutputStream outputStream = new FileOutputStream(getDownloadAbsoluteFile(fileName));
            ZipOutputStream out = new ZipOutputStream(outputStream);
            for(String name : fileNameList){
                String filePath = ProjectNameConfig.getInspectExportPath() + name;
                File file = new File(filePath);
                if(file.exists()){
                    ZipEntry entry = new ZipEntry(name);
                    out.putNextEntry(entry);
                    FileInputStream fis = new FileInputStream(file);
                    // 从输入流读取文件内容，并写入ZipOutputStream中
                    byte[] buffer = new byte[1024];
                    int len;
                    while ((len = fis.read(buffer)) > 0) {
                        out.write(buffer, 0, len);
                    }
                    // 关闭输入流
                    fis.close();
                    // 关闭输入流
                    out.closeEntry();
                }
            }
            out.flush();
            out.close();
            long zipEnd = System.currentTimeMillis();
            logger.info("压缩时间========" + (zipEnd - zipStart));
            return fileName;
        }catch (Exception e){
            logger.error("压缩包导出失败" + e);
            throw new CustomException("压缩包导出失败" + e);
        }

    }

    /**
     * 图片设置
     * @param mapValue 值
     * @param wb 表
     * @param sheet
     * @param row 行
     * @param col 列
     * @throws IOException
     */
    private void setImage(String mapValue,Workbook wb,Sheet sheet,int row,int col){
        try {
           /* BufferedImage bufferedImage = ImageIO.read(new URL(mapValue));
            Image image = ImgUtil.rotate(bufferedImage, -90);*/
            byte[] bytes = ImgUtil.toBytes(rotateImage(mapValue,-90),"png");
            int pictureIdx = wb.addPicture(bytes,Workbook.PICTURE_TYPE_PNG);
            CreationHelper helper = wb.getCreationHelper();  // 获取创建帮助类
            Drawing drawing = sheet.createDrawingPatriarch();   // 获取绘图父对象
            ClientAnchor anchor = helper.createClientAnchor();  // 创建客户端锚点
            // 图片插入坐标
            anchor.setCol1(col);  // 设置图片左上角的列数
            anchor.setRow1(row);  // 设置图片左上角的行数
            // 插入图片
            Picture pict = drawing.createPicture(anchor, pictureIdx);  // 在指定位置插入图片
            pict.resize(1,1);
        } catch (Exception e) {
            logger.error("图片设置失败:" + e);
        }

    }

    /**
     * 图片旋转
     * @param inputImagePath 图片链接
     * @param angle 角度
     * @throws IOException
     */
    public static BufferedImage rotateImage(String inputImagePath, double angle) throws IOException {
        // 读取图片
        BufferedImage image = ImageIO.read(new URL(inputImagePath));

        // 得到图片的中心点
        int width = image.getWidth();
        int height = image.getHeight();
        double rads = Math.toRadians(angle);
        double sin = Math.abs(Math.sin(rads));
        double cos = Math.abs(Math.cos(rads));
        int newWidth = (int) Math.floor(width * cos + height * sin),
                newHeight = (int) Math.floor(height * cos + width * sin);
        int imageType = image.getType();
        if(0 == imageType){
            imageType = BufferedImage.TYPE_INT_ARGB;
        }
        if (width <= 0 || height <= 0) {
            throw new IOException("图片尺寸异常: " + width + "x" + height);
        }

        if (newWidth < 1) newWidth = 1;
        if (newHeight < 1) newHeight = 1;

        // ==========================================
        // 使用 Graphics2D 旋转（100% 稳定，不依赖浮点数精度）
        // ==========================================
        BufferedImage rotated = new BufferedImage(newWidth, newHeight, imageType);
        Graphics2D g = rotated.createGraphics();

        // 高质量渲染
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
        g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);

        // 设置变换
        AffineTransform at = new AffineTransform();
        at.translate((newWidth - width) / 2.0, (newHeight - height) / 2.0);
        at.rotate(rads, width / 2.0, height / 2.0);
        g.drawImage(image, at, null);
        g.dispose();

        // 转标准 RGB（避免后续 POI 插入 Excel 时出问题）
        BufferedImage standard = new BufferedImage(newWidth, newHeight, imageType);
        Graphics2D g2 = standard.createGraphics();
        g2.drawImage(rotated, 0, 0, null);
        g2.dispose();

        return standard;
    }

    /**
     * 下载路径
     * @param filename
     * @return
     */
    public String getDownloadAbsoluteFile(String filename) {
        String downloadPath = ProjectNameConfig.getDownloadPath() + filename;
        File desc = new File(downloadPath);
        if (!desc.getParentFile().exists())
        {
            desc.getParentFile().mkdirs();
        }
        return downloadPath;
    }

    /**
     * 导出路径
     * @param filename
     * @return
     */
    public String getExportAbsoluteFile(String filename) {
        String exportPath = ProjectNameConfig.getInspectExportPath() + filename;
        File desc = new File(exportPath);
        if (!desc.getParentFile().exists())
        {
            desc.getParentFile().mkdirs();
        }
        return exportPath;
    }

    private void createTable(String template,Map<String,Object> map) throws IOException {
        InputStream source = this.getClass().getResourceAsStream("/excelTemplate/" + template);
        Workbook wb = WorkbookFactory.create(source);
        Sheet sheet = wb.getSheetAt(0);
        int rowNum = sheet.getLastRowNum();
        for(int i = 0;i < rowNum; i++){
            Row row = sheet.getRow(i);
            int cells = row.getPhysicalNumberOfCells();
            for(int ceNum = 0; ceNum < cells; ceNum++){
                Cell cell = row.getCell(ceNum);
                if(cell != null){
                    cell.setCellType(CellType.STRING);
                    String str = cell.getStringCellValue().trim();
                    // 要匹配的正则表达式
                    String regex = "%[a-zA-Z0-9]{0,50}%";
                    Pattern pattern = Pattern.compile(regex);
                    Matcher matcher = pattern.matcher(str);
                    while (matcher.find()){
                        String matcherStr = matcher.group().split("%")[1];
                        if(null != map.get(matcherStr)){
                            Object mapValue = map.get(matcherStr);
                            //判断是否为图片
                            if(matcherStr.contains("Url")){
                                setImage((String)mapValue,wb,sheet,i,ceNum);
                                cell.setCellValue("");
                            }else{
                                if(mapValue instanceof Boolean){
                                    if((boolean)map.get(matcherStr)){
                                        str = str.replace(matcher.group(),"\u2611");
                                    }else{
                                        str = str.replace(matcher.group(),"\u2610");
                                    }
                                }else{
                                    str = str.replace(matcher.group(),(String)mapValue);
                                }
                                cell.setCellValue(str);
                            }
                        }
                    }
                }
            }
        }
        String filename = (String) map.get("username") + map.get("createTime") + "安检单.xlsx";
        FileOutputStream out = new FileOutputStream(getExportAbsoluteFile(filename));
        wb.write(out);
        out.flush();
        out.close();
        fileNameList.add(filename);
    }
}
