package com.ylx.massage.utils;

import cn.hutool.core.util.StrUtil;
import com.ylx.common.exception.ServiceException;
import com.ylx.massage.domain.SensitiveWord;
import com.ylx.massage.enums.SensitiveWordCategoryEnum;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;

/**
 * Excel工具类
 * <p>
 * 提供Excel文件的读取和解析功能，支持敏感词数据的导入。
 * 支持.xls和.xlsx两种格式的Excel文件。
 * 支持处理合并单元格的情况。
 * </p>
 *
 * @author ylx
 * @version 1.0
 * @since 2024
 */
public class ExcelUtils {

    private static final Logger log = LoggerFactory.getLogger(ExcelUtils.class);

    /**
     * Excel列索引定义
     */
    private static final int COL_WORD = 0;        // 敏感词
    private static final int COL_CATEGORY = 1;    // 分类
    private static final int COL_LEVEL = 2;       // 等级
    private static final int COL_STATUS = 3;      // 状态
    private static final int COL_REMARK = 4;      // 备注

    /**
     * 解析敏感词Excel文件
     * <p>
     * 从Excel文件中读取敏感词数据并转换为SensitiveWord对象列表。
     * Excel文件格式要求：
     * - 第一行：表头（会被跳过）
     * - 列顺序：敏感词 | 分类 | 等级 | 状态 | 备注
     * - 第二行起：数据行
     * - 支持分类列使用合并单元格
     * </p>
     *
     * @param file 上传的Excel文件
     * @return List<SensitiveWord> 敏感词对象列表
     * @throws ServiceException 当文件格式错误或读取失败时抛出
     */
    public static List<SensitiveWord> parseSensitiveWordExcel(MultipartFile file) {
        if (file == null || file.isEmpty()) {
            throw new ServiceException("文件不能为空");
        }

        String fileName = file.getOriginalFilename();
        if (fileName == null) {
            throw new ServiceException("文件名不能为空");
        }

        // 验证文件格式
        if (!fileName.endsWith(".xls") && !fileName.endsWith(".xlsx")) {
            throw new ServiceException("文件格式错误，仅支持.xls或.xlsx格式的Excel文件");
        }

        List<SensitiveWord> wordList = new ArrayList<>();
        Workbook workbook = null;
        InputStream inputStream = null;

        try {
            inputStream = file.getInputStream();

            // 根据文件后缀创建不同类型的Workbook
            if (fileName.endsWith(".xlsx")) {
                workbook = new XSSFWorkbook(inputStream);
            } else {
                workbook = new HSSFWorkbook(inputStream);
            }

            // 获取第一个工作表
            Sheet sheet = workbook.getSheetAt(0);
            if (sheet == null) {
                throw new ServiceException("Excel文件中没有工作表");
            }

            log.info("开始解析Excel文件，总行数：{}", sheet.getLastRowNum());

            // 用于记录上一行的分类，处理合并单元格的情况
            String lastCategory = null;

            // 遍历所有行（从第二行开始，跳过表头）
            for (int i = 1; i <= sheet.getLastRowNum(); i++) {
                Row row = sheet.getRow(i);

                // 跳过空行
                if (row == null) {
                    continue;
                }

                try {
                    // 解析当前行数据，传入上一行的分类用于处理合并单元格
                    SensitiveWord word = parseRow(row, lastCategory);
                    if (word != null) {
                        // 更新lastCategory为当前行的分类，供下一行使用
                        lastCategory = word.getCategory();
                        wordList.add(word);
                    }
                } catch (Exception e) {
                    log.warn("解析第 {} 行数据失败，跳过该行。错误信息：{}", i + 1, e.getMessage());
                }
            }

            log.info("Excel文件解析完成，共解析 {} 条有效数据", wordList.size());
            return wordList;

        } catch (IOException e) {
            log.error("读取Excel文件失败", e);
            throw new ServiceException("读取Excel文件失败：" + e.getMessage());
        } finally {
            // 关闭资源
            if (workbook != null) {
                try {
                    workbook.close();
                } catch (IOException e) {
                    log.error("关闭Workbook失败", e);
                }
            }
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    log.error("关闭InputStream失败", e);
                }
            }
        }
    }

    /**
     * 解析Excel行数据
     * <p>
     * 将Excel的一行数据转换为SensitiveWord对象。
     * 处理合并单元格：当分类列为空时，使用上一行的分类值。
     * </p>
     *
     * @param row Excel行对象
     * @param lastCategory 上一行的分类值，用于处理合并单元格
     * @return SensitiveWord 敏感词对象，如果该行数据无效则返回null
     */
    private static SensitiveWord parseRow(Row row, String lastCategory) {
        SensitiveWord word = new SensitiveWord();

        try {
            // 1. 读取敏感词（必填）
            String wordText = getCellValueAsString(row.getCell(COL_WORD));
            if (StrUtil.isBlank(wordText)) {
                log.debug("第 {} 行：敏感词为空，跳过该行", row.getRowNum() + 1);
                return null;
            }
            word.setWord(wordText.trim());

            // 2. 读取分类（必填）
            // 处理合并单元格：如果当前行分类为空，使用上一行的分类
            String category = getCellValueAsString(row.getCell(COL_CATEGORY));
            if (StrUtil.isBlank(category)) {
                if (StrUtil.isNotBlank(lastCategory)) {
                    // 使用上一行的分类（处理合并单元格的情况）
                    log.debug("第 {} 行：分类列为空，使用上一行的分类：{}", row.getRowNum() + 1, lastCategory);
                    category = lastCategory;
                } else {
                    log.debug("第 {} 行：分类为空，使用默认分类", row.getRowNum() + 1);
                    category = SensitiveWordCategoryEnum.OTHER.getDesc();
                }
            } else {
                category = category.trim();
            }

            // 验证分类是否有效
            if (!isValidCategory(category)) {
                log.warn("第 {} 行：分类 '{}' 无效，使用默认分类", row.getRowNum() + 1, category);
                word.setCategory(SensitiveWordCategoryEnum.OTHER.getDesc());
            } else {
                word.setCategory(category);
            }

            // 3. 读取等级（可选，默认为1）
            String levelStr = getCellValueAsString(row.getCell(COL_LEVEL));
            if (StrUtil.isNotBlank(levelStr)) {
                try {
                    int level = Integer.parseInt(levelStr.trim());
                    if (level < 1 || level > 3) {
                        log.warn("第 {} 行：等级 {} 无效，使用默认值1", row.getRowNum() + 1, level);
                        word.setLevel(1);
                    } else {
                        word.setLevel(level);
                    }
                } catch (NumberFormatException e) {
                    log.warn("第 {} 行：等级格式错误 '{}', 使用默认值1", row.getRowNum() + 1, levelStr);
                    word.setLevel(1);
                }
            } else {
                word.setLevel(1);
            }

            // 4. 读取状态（可选，默认为1-启用）
            String statusStr = getCellValueAsString(row.getCell(COL_STATUS));
            if (StrUtil.isNotBlank(statusStr)) {
                try {
                    int status = Integer.parseInt(statusStr.trim());
                    if (status != 0 && status != 1) {
                        log.warn("第 {} 行：状态 {} 无效，使用默认值1", row.getRowNum() + 1, status);
                        word.setStatus(1);
                    } else {
                        word.setStatus(status);
                    }
                } catch (NumberFormatException e) {
                    log.warn("第 {} 行：状态格式错误 '{}', 使用默认值1", row.getRowNum() + 1, statusStr);
                    word.setStatus(1);
                }
            } else {
                word.setStatus(1);
            }

            // 5. 读取备注（可选）
            String remark = getCellValueAsString(row.getCell(COL_REMARK));
            if (StrUtil.isNotBlank(remark)) {
                word.setRemark(remark.trim());
            }

            return word;
        } catch (Exception e) {
            log.error("解析第 {} 行数据时发生错误", row.getRowNum() + 1, e);
            return null;
        }
    }

    /**
     * 获取单元格的字符串值
     * <p>
     * 处理不同类型的单元格，返回字符串表示。
     * </p>
     *
     * @param cell 单元格对象
     * @return String 单元格的字符串值，如果单元格为空则返回空字符串
     */
    private static String getCellValueAsString(Cell cell) {
        if (cell == null) {
            return "";
        }

        switch (cell.getCellType()) {
            case STRING:
                return cell.getStringCellValue().trim();

            case NUMERIC:
                if (DateUtil.isCellDateFormatted(cell)) {
                    return cell.getDateCellValue().toString();
                } else {
                    // 数字类型，转换为字符串（去除小数点）
                    DecimalFormat df = new DecimalFormat("0");
                    return df.format(cell.getNumericCellValue());
                }

            case BOOLEAN:
                return String.valueOf(cell.getBooleanCellValue());

            case FORMULA:
                try {
                    return cell.getStringCellValue();
                } catch (Exception e) {
                    try {
                        DecimalFormat df = new DecimalFormat("0");
                        return df.format(cell.getNumericCellValue());
                    } catch (Exception ex) {
                        return "";
                    }
                }

            case BLANK:
                return "";

            default:
                return "";
        }
    }

    /**
     * 验证分类是否有效
     * <p>
     * 检查分类是否在预定义的分类枚举中。
     * </p>
     *
     * @param category 分类名称
     * @return 如果分类有效返回true，否则返回false
     */
    private static boolean isValidCategory(String category) {
        if (StrUtil.isBlank(category)) {
            return false;
        }

        for (SensitiveWordCategoryEnum categoryEnum : SensitiveWordCategoryEnum.values()) {
            if (categoryEnum.getDesc().equals(category)) {
                return true;
            }
        }

        return false;
    }
}
