package com.ruoyi.logistics.handler;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
import com.ruoyi.logistics.domain.dto.SfOrderImportDTO;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.xssf.usermodel.XSSFDataValidation;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;

public class SFOrderDynamicTemplateHandler {

    /**
     * 导出带动态下拉框的 Excel 模板
     *
     * @param response HTTP 响应对象
     * @param productCodes 产品类型下拉列表数据
     * @param goodsNames 物品名称下拉列表数据
     * @throws IOException IO 异常
     */
    public void exportDynamicTemplate(HttpServletResponse response,
            List<String> productCodes,
            List<String> goodsNames) throws IOException {

        // 设置响应头
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        String fileName = URLEncoder.encode("顺丰批量下单模板", "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");

        // 创建 Excel 写入器，注册自定义 SheetWriteHandler 和 RowWriteHandler
        EasyExcel.write(response.getOutputStream(), SfOrderImportDTO.class)
                .sheet("订单")
                .registerWriteHandler(createDropdownSheetHandler(productCodes, goodsNames))
                .registerWriteHandler(createTextFormatRowHandler())
                .doWrite(ArrayList::new);
    }

    /**
     * 创建下拉框数据验证处理器
     *
     * @param productCodes 产品类型下拉列表数据
     * @param goodsNames 物品名称下拉列表数据
     * @return SheetWriteHandler 处理器
     */
    private SheetWriteHandler createDropdownSheetHandler(List<String> productCodes,
            List<String> goodsNames) {
        return new SheetWriteHandler() {
            @Override
            public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder,
                                         WriteSheetHolder writeSheetHolder) {
                Sheet sheet = writeSheetHolder.getSheet();
                Workbook workbook = writeWorkbookHolder.getWorkbook();

                // 1. 为"物品名称"列（第 G 列，索引 6）添加下拉框
                if (goodsNames != null && !goodsNames.isEmpty()) {
                    goodsNames.add("");
                    addDropdownValidation(workbook, sheet, goodsNames, 6, "GoodsNames");
                }

                // 2. 为"产品类型"列（第 M 列，索引 12）添加下拉框
                if (productCodes != null && !productCodes.isEmpty()) {
                    addDropdownValidation(workbook, sheet, productCodes, 10, "ProductCodes");
                }
                // 5. 添加数值列的数据验证（不能为负数）
                // 物品重量（第 H 列，索引 7）
                addNumberValidation(workbook, sheet, 7, "物品重量(KG)");
                // 物品体积（第 I 列，索引 8）
                addNumberValidation(workbook, sheet, 8, "物品体积(m³)");
                // 物品数量（第 J 列，索引 9）
                addNumberValidation(workbook, sheet, 9, "物品数量(件)");
                // 保价金额（第 O 列，索引 14）
                addNumberValidation(workbook, sheet, 11, "保价金额(元)");

           /*     // 6. 添加时间列的数据验证（格式：yyyy-MM-dd HH:00:00）
                // 上门取件开始时间（第 K 列，索引 10）
                addDateTimeValidation(workbook, sheet, 10, "上门取件开始时间");
                // 上门取件结束时间（第 L 列，索引 11）
                addDateTimeValidation(workbook, sheet, 11, "上门取件结束时间");*/
            }
        };
    }

    /**
     * 添加下拉框数据验证
     *
     * @param workbook 工作簿对象
     * @param sheet 工作表对象
     * @param dataList 下拉选项数据列表
     * @param columnIndex 列索引（从 0 开始）
     * @param rangeName 命名区域名称
     */
    private void addDropdownValidation(Workbook workbook, Sheet sheet,
            List<String> dataList,
    int columnIndex,
    String rangeName) {
        if (dataList == null || dataList.isEmpty()) {
            return;
        }

        // 检查是否已存在该命名区域
        Name existingName = workbook.getName(rangeName);
        if (existingName == null) {
            // 1. 创建隐藏的工作表存储下拉选项数据
            String hiddenSheetName = "_hidden_" + rangeName;
            Sheet hiddenSheet = workbook.createSheet(hiddenSheetName);

            // 填充数据到隐藏工作表的第 1 列
            for (int i = 0; i < dataList.size(); i++) {
                Row row = hiddenSheet.createRow(i);
                Cell cell = row.createCell(0);
                cell.setCellValue(dataList.get(i));
            }

            // 隐藏该工作表
            workbook.setSheetHidden(workbook.getSheetIndex(hiddenSheet), true);

            // 2. 创建命名区域
            Name namedCell = workbook.createName();
            namedCell.setNameName(rangeName);
            String formula = hiddenSheet.getSheetName() + "!$A$1:$A$" + dataList.size();
            namedCell.setRefersToFormula(formula);
        }

        // 3. 设置数据验证规则
        DataValidationHelper helper = sheet.getDataValidationHelper();
        DataValidationConstraint constraint = helper.createFormulaListConstraint(rangeName);

        // 设置下拉框应用范围（从第 2 行开始，第 1 行是标题）
        CellRangeAddressList addressList = new CellRangeAddressList(1, 1000, columnIndex, columnIndex);

        DataValidation validation = helper.createValidation(constraint, addressList);
        configureValidation(validation);

        sheet.addValidationData(validation);
    }

    /**
     * 为已有命名区域的列添加下拉框数据验证
     *
     * @param workbook 工作簿对象
     * @param sheet 工作表对象
     * @param columnIndex 列索引（从 0 开始）
     * @param rangeName 已存在的命名区域名称
     */
    private void addDropdownValidationToExistingRange(Workbook workbook, Sheet sheet,
    int columnIndex,
    String rangeName) {
        // 验证命名区域是否存在
        Name existingName = workbook.getName(rangeName);
        if (existingName == null) {
            return; // 如果命名区域不存在，直接返回
        }

        // 设置数据验证规则
        DataValidationHelper helper = sheet.getDataValidationHelper();
        DataValidationConstraint constraint = helper.createFormulaListConstraint(rangeName);

        // 设置下拉框应用范围（从第 2 行开始，第 1 行是标题）
        CellRangeAddressList addressList = new CellRangeAddressList(1, 1000, columnIndex, columnIndex);

        DataValidation validation = helper.createValidation(constraint, addressList);
        configureValidation(validation);

        sheet.addValidationData(validation);
    }

    /**
     * 配置数据验证的通用属性
     *
     * @param validation 数据验证对象
     */
    private void configureValidation(DataValidation validation) {
        // 允许空白输入
        validation.setSuppressDropDownArrow(true);
        validation.setShowErrorBox(true);
        validation.setShowPromptBox(true);

        // 处理 POI 的兼容性问题
        if (validation instanceof XSSFDataValidation) {
            ((XSSFDataValidation) validation).setSuppressDropDownArrow(true);
            ((XSSFDataValidation) validation).setShowErrorBox(true);
        }
    }


    /**
     * 获取是/否选项下拉列表
     */
    private List<String> getYesNoOptions() {
        return java.util.Arrays.asList("是", "否");
    }

    /**
     * 添加数值数据验证（必须大于 0）
     *
     * @param workbook 工作簿对象
     * @param sheet 工作表对象
     * @param columnIndex 列索引（从 0 开始）
     * @param fieldName 字段名称（用于错误提示）
     */
    private void addNumberValidation(Workbook workbook, Sheet sheet,
    int columnIndex, String fieldName) {
        DataValidationHelper helper = sheet.getDataValidationHelper();

        // 使用自定义公式验证：数值必须大于 0
        String excelCol = columnToLetter(columnIndex);
        String formula = excelCol + "2>0";

        DataValidationConstraint constraint = helper.createCustomConstraint(formula);

        // 设置验证范围（从第 2 行开始，第 1 行是标题）
        CellRangeAddressList addressList = new CellRangeAddressList(1, 1000, columnIndex, columnIndex);

        DataValidation validation = helper.createValidation(constraint, addressList);

        // 设置错误提示
        validation.setErrorStyle(DataValidation.ErrorStyle.STOP);
        validation.createErrorBox("输入值无效", fieldName + "必须大于 0，请输入正数！");
        validation.setShowErrorBox(true);

        // 允许空白输入
        validation.setSuppressDropDownArrow(true);

        if (validation instanceof XSSFDataValidation) {
            ((XSSFDataValidation) validation).setSuppressDropDownArrow(true);
            ((XSSFDataValidation) validation).setShowErrorBox(true);
        }

        sheet.addValidationData(validation);
    }

    /**
     * 添加日期时间数据验证（格式：yyyy-MM-dd HH:00:00）
     *
     * @param workbook 工作簿对象
     * @param sheet 工作表对象
     * @param columnIndex 列索引（从 0 开始）
     * @param fieldName 字段名称（用于错误提示）
     */
    private void addDateTimeValidation(Workbook workbook, Sheet sheet,
    int columnIndex, String fieldName) {
        DataValidationHelper helper = sheet.getDataValidationHelper();

        // 将列索引转换为 Excel 列字母（如 K、L）
        String excelCol = columnToLetter(columnIndex);

        // 构建验证公式：严格按照 yyyy-MM-dd HH:00:00 格式
        // 验证要点：
        // 1. 总长度必须为 19 个字符
        // 2. 固定位置的字符必须是：- - 空格 : :
        // 3. 分钟 (15-16 位) 和秒 (18-19 位) 必须是 00
        // 4. 年、月、日、时必须是数字
        String formula = "AND(" +
                "LEN(" + excelCol + "2)=19," +                                    // 长度=19
                "MID(" + excelCol + "2,5,1)=\"-\"," +                             // 第 5 位=-
                "MID(" + excelCol + "2,8,1)=\"-\"," +                             // 第 8 位=-
                "MID(" + excelCol + "2,11,1)=\" \"," +                            // 第 11 位=空格
                "MID(" + excelCol + "2,14,1)=\":\"," +                            // 第 14 位=:
                "MID(" + excelCol + "2,17,1)=\":\"," +                            // 第 17 位=:
                "MID(" + excelCol + "2,15,2)=\"00\"," +                           // 分钟=00
                "MID(" + excelCol + "2,18,2)=\"00\"," +                           // 秒=00
                "--MID(" + excelCol + "2,1,4)>=1900," +                           // 年>=1900
                "--MID(" + excelCol + "2,1,4)<=9999," +                           // 年<=9999
                "--MID(" + excelCol + "2,6,2)>=1," +                              // 月>=1
                "--MID(" + excelCol + "2,6,2)<=12," +                             // 月<=12
                "--MID(" + excelCol + "2,9,2)>=1," +                              // 日>=1
                "--MID(" + excelCol + "2,9,2)<=31," +                             // 日<=31
                "--MID(" + excelCol + "2,12,2)>=0," +                             // 时>=0
                "--MID(" + excelCol + "2,12,2)<=23" +                             // 时<=23
                ")";

        DataValidationConstraint constraint = helper.createCustomConstraint(formula);

        // 设置验证范围（从第 2 行开始，第 1 行是标题）
        CellRangeAddressList addressList = new CellRangeAddressList(1, 1000, columnIndex, columnIndex);

        DataValidation validation = helper.createValidation(constraint, addressList);

        // 设置输入提示，引导用户输入格式
        validation.createPromptBox(fieldName + "输入提示", "请输入日期和时间，格式：yyyy-MM-dd HH:00:00（例如：2026-01-01 10:00:00）");
        validation.setShowPromptBox(true);

        // 设置错误提示
        validation.setErrorStyle(DataValidation.ErrorStyle.STOP);
        validation.createErrorBox("输入值无效", fieldName + "格式不正确，请严格按照 yyyy-MM-dd HH:00:00 格式输入（分钟和秒固定为 00）！");
        validation.setShowErrorBox(true);

        // 允许空白输入
        validation.setSuppressDropDownArrow(true);

        if (validation instanceof XSSFDataValidation) {
            ((XSSFDataValidation) validation).setSuppressDropDownArrow(true);
            ((XSSFDataValidation) validation).setShowErrorBox(true);
        }

        sheet.addValidationData(validation);
    }

    /**
     * 将列索引转换为 Excel 列字母
     *
     * @param columnIndex 列索引（从 0 开始）
     * @return Excel 列字母
     */
    private String columnToLetter(int columnIndex) {
        StringBuilder result = new StringBuilder();
        int index = columnIndex + 1; // 转换为从 1 开始
        while (index > 0) {
            index--;
            result.insert(0, (char) ('A' + index % 26));
            index /= 26;
        }
        return result.toString();
    }

    /**
     * 创建文本格式的 RowWriteHandler
     * 用于设置上门取件开始时间和结束时间列为文本格式
     *
     * @return RowWriteHandler 处理器
     */
    private SheetWriteHandler createTextFormatRowHandler() {
        return new SheetWriteHandler() {
            @Override
            public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
                Sheet sheet = writeSheetHolder.getSheet();
                DataFormat dataFormat = writeWorkbookHolder.getWorkbook().createDataFormat();

                // 创建文本格式单元格样式
                CellStyle textCellStyle = writeWorkbookHolder.getWorkbook().createCellStyle();
                textCellStyle.setDataFormat(dataFormat.getFormat("@")); // 等同于setDataFormat(TEXT_FORMAT_CODE)

                // 为sheet的所有列设置默认文本格式（这里设置前100列，可根据需求调整范围）
                int maxColumnNum = 100;
                for (int i = 0; i < maxColumnNum; i++) {
                    sheet.setDefaultColumnStyle(i, textCellStyle);
                }
            }
        };
    }
}
