package com.casic.missiles.utils;

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class ExcelCopyUtil {

    /**
     * 从源Excel文件中复制指定的行，并粘贴到目标Excel文件的指定Sheet页中对应的行
     *
     * @param sourceFilePath   源Excel文件路径
     * @param sourceSheetName  源Excel文件的Sheet页名称
     * @param targetFilePath   目标Excel文件路径
     * @param targetSheetName  目标Excel文件的Sheet页名称
     * @param sourceRowIndices 需要复制的源文件行索引范围（起始和结束，从0开始）
     * @param targetRowIndices 需要粘贴的目标文件行索引范围（起始和结束，从0开始）
     * @throws IOException 文件读写异常
     */
    public static void copyRowsToExcel(String sourceFilePath, String sourceSheetName,
                                       String targetFilePath, String targetSheetName,
                                       List<Integer> sourceRowIndices, List<Integer> targetRowIndices,
                                       List<String> linkedSheetNames) throws IOException {
        // 参数校验
        if (sourceRowIndices.size() != 2 || targetRowIndices.size() != 2) {
            throw new IllegalArgumentException("源行索引范围和目标行索引范围必须包含起始和结束两个值。");
        }

        int sourceStart = sourceRowIndices.get(0);
        int sourceEnd = sourceRowIndices.get(1);
        int targetStart = targetRowIndices.get(0);
        int targetEnd = targetRowIndices.get(1);

        if (sourceEnd < sourceStart || targetEnd < targetStart) {
            throw new IllegalArgumentException("起始索引必须小于或等于结束索引。");
        }

        if ((sourceEnd - sourceStart) != (targetEnd - targetStart)) {
            throw new IllegalArgumentException("源行索引范围和目标行索引范围的长度必须相同。");
        }

        // 生成行索引列表
        List<Integer> sourceRows = new ArrayList<>();
        List<Integer> targetRows = new ArrayList<>();
        for (int i = 0; i <= sourceEnd - sourceStart; i++) {
            sourceRows.add(sourceStart + i);
            targetRows.add(targetStart + i);
        }

        // 调用现有的复制逻辑
        copyRowsToAnotherExcel(sourceFilePath, sourceSheetName, targetFilePath, targetSheetName, sourceRows, targetRows, linkedSheetNames);
    }

    private static void copyRowsToAnotherExcel(String sourceFilePath, String sourceSheetName,
                                               String targetFilePath, String targetSheetName,
                                               List<Integer> sourceRowIndices, List<Integer> targetRowIndices,
                                               List<String> linkedSheetNames) throws IOException {
        if (sourceRowIndices.size() != targetRowIndices.size()) {
            throw new IllegalArgumentException("源行索引列表和目标行索引列表的长度必须相同。");
        }

        try (FileInputStream fis = new FileInputStream(sourceFilePath);
             Workbook sourceWorkbook = WorkbookFactory.create(fis);
             FileInputStream targetFis = new FileInputStream(targetFilePath);
             Workbook targetWorkbook = WorkbookFactory.create(targetFis);
             FileOutputStream fos = new FileOutputStream(targetFilePath)) {

            // 获取源Sheet页
            Sheet sourceSheet = sourceWorkbook.getSheet(sourceSheetName);
            if (sourceSheet == null) {
                throw new IllegalArgumentException("Sheet '" + sourceSheetName + "' not found in source file.");
            }

            // 获取目标Sheet页
            Sheet targetSheet = targetWorkbook.getSheet(targetSheetName);
            if (targetSheet == null) {
                throw new IllegalArgumentException("Sheet '" + targetSheetName + "' not found in target file.");
            }

            // 创建线程池
            ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

            // 遍历需要复制的行
            for (int i = 0; i < sourceRowIndices.size(); i++) {
                int sourceRowIndex = sourceRowIndices.get(i);
                int targetRowIndex = targetRowIndices.get(i);

                // 提交任务到线程池
                executor.submit(() -> {
                    try {
                        copyRow(sourceSheet, targetSheet, sourceRowIndex, targetRowIndex, targetWorkbook);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                });
            }

            // 关闭线程池并等待所有任务完成
            executor.shutdown();
            executor.awaitTermination(1, TimeUnit.HOURS);

            // 复制合并单元格（避免重叠）
            copyMergedRegions(sourceSheet, targetSheet, sourceRowIndices, targetRowIndices);

            // 更新指定 Sheet 页的链接内容
            updateLinkedReferences(targetWorkbook, targetSheetName, targetRowIndices, sourceRowIndices, linkedSheetNames);

            // 强制Excel在打开文件时重新计算公式
            targetWorkbook.setForceFormulaRecalculation(true);

            // 写入目标文件
            targetWorkbook.write(fos);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new RuntimeException("Thread interrupted", e);
        }
    }

    private static void copyRow(Sheet sourceSheet, Sheet targetSheet, int sourceRowIndex, int targetRowIndex, Workbook targetWorkbook) {
        // 获取源行
        Row sourceRow = sourceSheet.getRow(sourceRowIndex);
        if (sourceRow == null) {
            return; // 如果行不存在，跳过
        }

        // 获取或创建目标行
        Row targetRow = targetSheet.getRow(targetRowIndex);
        if (targetRow == null) {
            targetRow = targetSheet.createRow(targetRowIndex);
        }

        // 复制行高
        targetRow.setHeight(sourceRow.getHeight());

        // 复制每个单元格
        for (int cellIndex = 0; cellIndex < sourceRow.getLastCellNum(); cellIndex++) {
            Cell sourceCell = sourceRow.getCell(cellIndex);
            if (sourceCell == null) {
                continue; // 如果单元格不存在，跳过
            }

            // 获取或创建目标单元格
            Cell targetCell = targetRow.getCell(cellIndex);
            if (targetCell == null) {
                targetCell = targetRow.createCell(cellIndex);
            }

            // 复制单元格内容、样式和边框
            copyCell(sourceCell, targetCell, targetWorkbook, sourceRowIndex, targetRowIndex);
        }

        // 复制行样式（如果有）
        if (sourceRow.getRowStyle() != null) {
            targetRow.setRowStyle(sourceRow.getRowStyle());
        }
    }

    /**
     * 修复公式中的无效函数名称和语法
     *
     * @param formula 原始公式
     * @return 修复后的公式
     */
    private static String fixFormula(String formula) {
        // 使用正则表达式匹配所有类似 IF5、IF10、IF15、IF45 的无效函数名称，并替换为 IF
        formula = formula.replaceAll("IF\\d+", "IF");

        // 修复 IF 函数的语法（确保符合 IF(condition, value_if_true, value_if_false) 格式）
        if (formula.startsWith("IF(")) {
            formula = formula.replace("IF(", "IF(");
        }

        return formula;
    }

    private static void copyCell(Cell sourceCell, Cell targetCell, Workbook targetWorkbook,
                                 int sourceRowIndex, int targetRowIndex) {
        // 复制单元格样式
        CellStyle sourceCellStyle = sourceCell.getCellStyle();
        if (sourceCellStyle != null) {
            // 如果源单元格有样式，则克隆样式
            CellStyle targetCellStyle = targetWorkbook.createCellStyle();
            targetCellStyle.cloneStyleFrom(sourceCellStyle);
            targetCell.setCellStyle(targetCellStyle);
        } else {
            // 如果源单元格没有样式，则设置为默认样式
            targetCell.setCellStyle(targetWorkbook.createCellStyle());
        }

        // 复制单元格内容
        switch (sourceCell.getCellType()) {
            case STRING:
                targetCell.setCellValue(sourceCell.getStringCellValue());
                break;
            case NUMERIC:
                targetCell.setCellValue(sourceCell.getNumericCellValue());
                break;
            case BOOLEAN:
                targetCell.setCellValue(sourceCell.getBooleanCellValue());
                break;
            case FORMULA:
                // 调整公式中的单元格引用
                String adjustedFormula = adjustFormulaReferences(sourceCell.getCellFormula(), sourceRowIndex, targetRowIndex);
                // 修复公式中的无效函数名称
                String fixedFormula = fixFormula(adjustedFormula);
                try {
                    // 尝试设置公式
                    targetCell.setCellFormula(fixedFormula);
                } catch (Exception e) {
                    // 如果公式解析失败，记录错误并保留原始公式
                    System.err.println("Failed to parse formula: " + fixedFormula);
                    targetCell.setCellFormula(adjustedFormula);
                }
                break;
            case BLANK:
                targetCell.setBlank();
                break;
            default:
                throw new IllegalStateException("Unsupported cell type: " + sourceCell.getCellType());
        }

        // 复制单元格注释（如果有）
        if (sourceCell.getCellComment() != null) {
            targetCell.setCellComment(sourceCell.getCellComment());
        }

        // 复制单元格超链接（如果有）
        if (sourceCell.getHyperlink() != null) {
            targetCell.setHyperlink(sourceCell.getHyperlink());
        }
    }

    /**
     * 调整公式中的单元格引用
     *
     * @param formula         源公式
     * @param sourceRowIndex  源行索引
     * @param targetRowIndex  目标行索引
     * @return 调整后的公式
     */
    private static String adjustFormulaReferences(String formula, int sourceRowIndex, int targetRowIndex) {
        // 计算行偏移量
        int rowOffset = targetRowIndex - sourceRowIndex;

        // 调整公式中的行号
        StringBuilder adjustedFormula = new StringBuilder();
        int length = formula.length();
        for (int i = 0; i < length; i++) {
            char c = formula.charAt(i);
            if (c == '$') {
                // 处理绝对引用符号
                adjustedFormula.append(c);
                i++;
                if (i < length) {
                    c = formula.charAt(i);
                    if (Character.isLetter(c)) {
                        // 处理列绝对引用（例如 $A）
                        adjustedFormula.append(c);
                        while (i + 1 < length && Character.isLetterOrDigit(formula.charAt(i + 1))) {
                            adjustedFormula.append(formula.charAt(++i));
                        }
                    } else if (Character.isDigit(c)) {
                        // 处理行绝对引用（例如 $1）
                        adjustedFormula.append(c);
                        while (i + 1 < length && Character.isDigit(formula.charAt(i + 1))) {
                            adjustedFormula.append(formula.charAt(++i));
                        }
                    }
                }
            } else if (Character.isLetter(c)) {
                // 处理相对引用（例如 A1）
                StringBuilder cellRef = new StringBuilder();
                cellRef.append(c);
                while (i + 1 < length && Character.isLetterOrDigit(formula.charAt(i + 1))) {
                    cellRef.append(formula.charAt(++i));
                }

                // 解析行号并调整
                String cellRefStr = cellRef.toString();
                int rowNumber = 0;
                int colNumber = 0;
                for (int j = 0; j < cellRefStr.length(); j++) {
                    if (Character.isDigit(cellRefStr.charAt(j))) {
                        rowNumber = rowNumber * 10 + (cellRefStr.charAt(j) - '0');
                    } else {
                        colNumber = colNumber * 26 + (cellRefStr.charAt(j) - 'A' + 1);
                    }
                }

                // 调整行号
                rowNumber += rowOffset;

                // 重新构建单元格引用
                adjustedFormula.append(getCellReference(colNumber, rowNumber));
            } else {
                adjustedFormula.append(c);
            }
        }

        return adjustedFormula.toString();
    }

    /**
     * 根据列号和行号获取单元格引用（例如 A1, B2）
     *
     * @param colNumber 列号（从1开始）
     * @param rowNumber 行号（从1开始）
     * @return 单元格引用
     */
    private static String getCellReference(int colNumber, int rowNumber) {
        StringBuilder cellRef = new StringBuilder();
        while (colNumber > 0) {
            colNumber--;
            cellRef.insert(0, (char) ('A' + (colNumber % 26)));
            colNumber /= 26;
        }
        cellRef.append(rowNumber);
        return cellRef.toString();
    }

    /**
     * 复制合并单元格（避免重叠）
     *
     * @param sourceSheet      源Sheet页
     * @param targetSheet      目标Sheet页
     * @param sourceRowIndices 源行索引列表
     * @param targetRowIndices 目标行索引列表
     */
    private static void copyMergedRegions(Sheet sourceSheet, Sheet targetSheet,
                                          List<Integer> sourceRowIndices, List<Integer> targetRowIndices) {
        for (int i = 0; i < sourceSheet.getNumMergedRegions(); i++) {
            CellRangeAddress mergedRegion = sourceSheet.getMergedRegion(i);
            for (int j = 0; j < sourceRowIndices.size(); j++) {
                int sourceRowIndex = sourceRowIndices.get(j);
                int targetRowIndex = targetRowIndices.get(j);

                // 如果合并区域包含源行，则在目标Sheet中创建对应的合并区域
                if (mergedRegion.getFirstRow() <= sourceRowIndex && mergedRegion.getLastRow() >= sourceRowIndex) {
                    // 计算目标合并区域的行范围
                    int firstRow = targetRowIndex - (sourceRowIndex - mergedRegion.getFirstRow());
                    int lastRow = targetRowIndex + (mergedRegion.getLastRow() - sourceRowIndex);

                    // 创建新的合并区域
                    CellRangeAddress newMergedRegion = new CellRangeAddress(
                            firstRow, lastRow,
                            mergedRegion.getFirstColumn(), mergedRegion.getLastColumn()
                    );

                    // 检查目标Sheet中是否存在重叠的合并区域
                    if (!isMergedRegionOverlapping(targetSheet, newMergedRegion)) {
                        targetSheet.addMergedRegion(newMergedRegion);
                    }
                }
            }
        }
    }

    /**
     * 检查目标Sheet中是否存在与指定合并区域重叠的区域
     *
     * @param sheet        目标Sheet页
     * @param mergedRegion 需要检查的合并区域
     * @return 是否存在重叠
     */
    private static boolean isMergedRegionOverlapping(Sheet sheet, CellRangeAddress mergedRegion) {
        for (int i = 0; i < sheet.getNumMergedRegions(); i++) {
            CellRangeAddress existingRegion = sheet.getMergedRegion(i);
            if (existingRegion.intersects(mergedRegion)) {
                return true; // 存在重叠
            }
        }
        return false; // 不存在重叠
    }

    /**
     * 更新目标文件中指定 Sheet 页的链接内容，使其随偏移量变化
     *
     * @param targetWorkbook     目标工作簿
     * @param targetSheetName    目标 Sheet 页名称
     * @param targetRowIndices   目标行索引列表
     * @param sourceRowIndices   源行索引列表
     * @param linkedSheetNames   需要更新链接的 Sheet 页名称列表
     */
    private static void updateLinkedReferences(Workbook targetWorkbook, String targetSheetName,
                                               List<Integer> targetRowIndices, List<Integer> sourceRowIndices,
                                               List<String> linkedSheetNames) {
        // 获取目标 Sheet 页
        Sheet targetSheet = targetWorkbook.getSheet(targetSheetName);
        if (targetSheet == null) {
            throw new IllegalArgumentException("Sheet '" + targetSheetName + "' not found in target file.");
        }

        // 遍历指定的 Sheet 页
        for (String sheetName : linkedSheetNames) {
            Sheet sheet = targetWorkbook.getSheet(sheetName);
            if (sheet == null) {
                System.err.println("Sheet '" + sheetName + "' not found in target file. Skipping...");
                continue;
            }

            // 遍历 Sheet 页中的所有行和单元格
            for (Row row : sheet) {
                if (row == null) {
                    continue;
                }
                for (Cell cell : row) {
                    if (cell == null || cell.getCellType() != CellType.FORMULA) {
                        continue; // 跳过非公式单元格
                    }

                    // 获取公式并调整引用
                    String formula = cell.getCellFormula();
                    for (int i = 0; i < sourceRowIndices.size(); i++) {
                        int sourceRowIndex = sourceRowIndices.get(i);
                        int targetRowIndex = targetRowIndices.get(i);

                        // 调整公式中的单元格引用
                        String adjustedFormula = adjustFormulaReferences(formula, sourceRowIndex, targetRowIndex);

                        // 修复公式中的无效函数名称和语法
                        String fixedFormula = fixFormula(adjustedFormula);

                        // 尝试设置公式
                        try {
                            cell.setCellFormula(fixedFormula);
                        } catch (Exception e) {
                            // 如果公式解析失败，记录错误并保留原始公式
                            System.err.println("Failed to parse formula: " + fixedFormula);
                            System.err.println("Error: " + e.getMessage());
                            cell.setCellFormula(adjustedFormula); // 保留调整后的公式
                        }

                        formula = adjustedFormula; // 更新公式，以便后续调整
                    }
                }
            }
        }
    }
}