package com.yd.oss.service.service.impl;

import com.yd.oss.feign.annotation.ExcelCollection;
import com.yd.oss.feign.annotation.ExcelField;
import com.yd.oss.feign.annotation.ExcelSheet;
import com.yd.oss.service.service.ExcelParserService;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Excel通用解析器
 */
@Service
public class ExcelParserServiceImpl implements ExcelParserService {
    
    private static final Logger log = LoggerFactory.getLogger(ExcelParserServiceImpl.class);

    /**
     * 解析Excel文件（多Sheet页版本）
     * @param file 上传的Excel文件
     * @param sheetClasses 每个Sheet页对应的类类型
     * @return 包含所有Sheet页解析结果的Map，key为Sheet索引
     */
    @Override
    public Map<Integer, Object> parseExcelWithMultipleSheets(MultipartFile file, Class<?>... sheetClasses) throws Exception {
        Map<Integer, Object> resultMap = new HashMap<>();
        Workbook workbook = WorkbookFactory.create(file.getInputStream());
        
        try {
            for (Class<?> clazz : sheetClasses) {
                ExcelSheet sheetAnnotation = clazz.getAnnotation(ExcelSheet.class);
                if (sheetAnnotation == null) {
                    log.warn("类 {} 缺少@ExcelSheet注解，跳过处理", clazz.getSimpleName());
                    continue;
                }
                
                Sheet sheet;
                if (!sheetAnnotation.sheetName().isEmpty()) {
                    sheet = workbook.getSheet(sheetAnnotation.sheetName());
                } else {
                    sheet = workbook.getSheetAt(sheetAnnotation.sheetIndex());
                }
                
                if (sheet == null) {
                    log.warn("Sheet {} 不存在", 
                             !sheetAnnotation.sheetName().isEmpty() ? 
                             sheetAnnotation.sheetName() : sheetAnnotation.sheetIndex());
                    continue;
                }
                
                Object instance = clazz.getDeclaredConstructor().newInstance();
                
                // 解析普通字段
                parseFieldsWithMergedCells(sheet, instance);
                
                // 解析集合字段
                parseCollectionFields(sheet, instance);
                
                resultMap.put(sheetAnnotation.sheetIndex(), instance);
            }
            
            return resultMap;
        } finally {
            workbook.close();
        }
    }

    /**
     * 解析单个Sheet页
     * @param file
     * @param clazz
     * @param <T>
     * @return
     * @throws Exception
     */
    public <T> T parseExcel(MultipartFile file, Class<T> clazz) throws Exception {
        Workbook workbook = WorkbookFactory.create(file.getInputStream());
        try {
            // 获取Sheet信息
            ExcelSheet sheetAnnotation = clazz.getAnnotation(ExcelSheet.class);
            Sheet sheet;
            
            if (sheetAnnotation != null) {
                if (!sheetAnnotation.sheetName().isEmpty()) {
                    sheet = workbook.getSheet(sheetAnnotation.sheetName());
                } else {
                    sheet = workbook.getSheetAt(sheetAnnotation.sheetIndex());
                }
            } else {
                sheet = workbook.getSheetAt(0); // 默认第一个Sheet
            }
            
            if (sheet == null) {
                throw new RuntimeException("Sheet not found");
            }
            
            T instance = clazz.getDeclaredConstructor().newInstance();
            
            // 解析普通字段
            parseFieldsWithMergedCells(sheet, instance);
            
            // 解析集合字段
            parseCollectionFields(sheet, instance);
            
            return instance;
        } finally {
            workbook.close();
        }
    }

    /**
     * 处理合并单元格的字段解析
     * @param sheet
     * @param instance
     */
    private void parseFieldsWithMergedCells(Sheet sheet, Object instance) {
        // 获取所有合并区域
        List<CellRangeAddress> mergedRegions = sheet.getMergedRegions();

        for (Field field : instance.getClass().getDeclaredFields()) {
            ExcelField excelField = field.getAnnotation(ExcelField.class);
            if (excelField != null) {
                try {
                    int valueRow = excelField.valueRow() >= 0 ? excelField.valueRow() : excelField.titleRow();
                    int valueCol = excelField.valueCol() >= 0 ? excelField.valueCol() : excelField.titleCol() + 1;

                    Row row = sheet.getRow(valueRow);
                    if (row == null) continue;

                    // 检查是否为合并单元格
                    CellRangeAddress mergedRegion = findMergedRegion(mergedRegions, valueRow, valueCol);

                    String cellValue;
                    if (mergedRegion != null) {
                        // 合并单元格，取第一个单元格的值
                        Cell firstCell = sheet.getRow(mergedRegion.getFirstRow())
                                .getCell(mergedRegion.getFirstColumn());
                        cellValue = getCellValueAsString(firstCell);
                    } else {
                        // 普通单元格
                        Cell cell = row.getCell(valueCol);
                        cellValue = cell != null ? getCellValueAsString(cell) : null;
                    }

                    if (cellValue == null || cellValue.trim().isEmpty()) {
                        continue;
                    }

                    // 转换单元格值
                    Object value = convertStringValue(cellValue, field.getType(), excelField.dateFormat());

                    // 设置字段值
                    field.setAccessible(true);
                    field.set(instance, value);
                } catch (Exception e) {
                    log.warn("设置字段 {} 值失败: {}", field.getName(), e.getMessage());
                }
            }
        }
    }

    /**
     * 查找包含指定行列的合并区域
     * @param mergedRegions
     * @param row
     * @param column
     * @return
     */
    private CellRangeAddress findMergedRegion(List<CellRangeAddress> mergedRegions, int row, int column) {
        for (CellRangeAddress region : mergedRegions) {
            if (region.isInRange(row, column)) {
                return region;
            }
        }
        return null;
    }

    /**
     * 将单元格值转换为字符串
     * @param cell 单元格对象
     * @return 单元格值的字符串表示，若单元格为null则返回null
     */
    private String getCellValueAsString(Cell cell) {
        if (cell == null) {
            return null;
        }
        switch (cell.getCellType()) {
            case STRING:
                return cell.getStringCellValue().trim();
            case NUMERIC:
                if (DateUtil.isCellDateFormatted(cell)) {
                    // 日期类型转换为字符串（可根据需要调整格式）
                    return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(cell.getDateCellValue());
                } else {
                    // 数字类型避免科学计数法，转换为字符串
                    return String.valueOf(cell.getNumericCellValue());
                }
            case BOOLEAN:
                return String.valueOf(cell.getBooleanCellValue());
            case FORMULA:
                try {
                    return cell.getStringCellValue().trim();
                } catch (Exception e) {
                    // 公式计算结果不是字符串时，尝试获取数值
                    return String.valueOf(cell.getNumericCellValue());
                }
            default:
                return "";
        }
    }

    /**
     * 解析普通字段
     * @param sheet
     * @param instance
     */
    private void parseFields(Sheet sheet, Object instance) {
        for (Field field : instance.getClass().getDeclaredFields()) {
            ExcelField excelField = field.getAnnotation(ExcelField.class);
            if (excelField != null) {
                try {
                    // 获取值单元格
                    int valueRow = excelField.valueRow() >= 0 ? excelField.valueRow() : excelField.titleRow();
                    int valueCol = excelField.valueCol() >= 0 ? excelField.valueCol() : excelField.titleCol() + 1;
                    
                    Row row = sheet.getRow(valueRow);
                    if (row == null) continue;
                    
                    Cell cell = row.getCell(valueCol);
                    if (cell == null) continue;
                    
                    // 转换单元格值
                    Object value = convertCellValue(cell, field.getType(), excelField.dateFormat());
                    
                    // 设置字段值
                    field.setAccessible(true);
                    field.set(instance, value);
                } catch (Exception e) {
                    log.warn("设置字段 {} 值失败: {}", field.getName(), e.getMessage());
                }
            }
        }
    }

    /**
     * 解析集合字段（增强版，支持动态结束行检测）
     * @param sheet
     * @param instance
     * @throws Exception
     */
    private void parseCollectionFields(Sheet sheet, Object instance) throws Exception {
        for (Field field : instance.getClass().getDeclaredFields()) {
            ExcelCollection collectionAnnotation = field.getAnnotation(ExcelCollection.class);
            if (collectionAnnotation != null) {
                List<Object> collectionData = new ArrayList<>();
                
                // 确定结束行（支持自动检测）
                int endRow = collectionAnnotation.endRow() >= 0 ? 
                    collectionAnnotation.endRow() : findCollectionEndRow(sheet, collectionAnnotation);
                
                // 遍历行，解析集合元素
                for (int rowNum = collectionAnnotation.startRow(); rowNum <= endRow; rowNum++) {
                    Row row = sheet.getRow(rowNum);
                    if (row == null || isRowEmpty(row)) {
                        continue; // 跳过空行
                    }
                    
                    try {
                        Object element = collectionAnnotation.type().getDeclaredConstructor().newInstance();
                        boolean hasData = false;
                        
                        // 解析元素字段
                        for (Field elementField : collectionAnnotation.type().getDeclaredFields()) {
                            ExcelField excelField = elementField.getAnnotation(ExcelField.class);
                            if (excelField != null) {
                                // 计算值所在列
                                int valueCol = excelField.valueCol() >= 0 ? 
                                    excelField.valueCol() : excelField.titleCol();
                                
                                Cell cell = row.getCell(valueCol);
                                if (cell != null) {
                                    Object value = convertCellValue(cell, elementField.getType(), excelField.dateFormat());
                                    elementField.setAccessible(true);
                                    elementField.set(element, value);
                                    hasData = true;
                                }
                            }
                        }
                        
                        if (hasData) {
                            collectionData.add(element);
                        }
                    } catch (Exception e) {
                        log.warn("解析集合元素失败: {}", e.getMessage());
                    }
                }
                
                // 设置集合字段值
                field.setAccessible(true);
                field.set(instance, collectionData);
            }
        }
    }

    /**
     * 自动检测集合的结束行
     * @param sheet
     * @param collectionAnnotation
     * @return
     */
    private int findCollectionEndRow(Sheet sheet, ExcelCollection collectionAnnotation) {
        int endRow = collectionAnnotation.startRow();
        int maxEmptyRows = 5; // 连续空行的最大数量
        
        // 获取所有需要检查的列
        Set<Integer> columnsToCheck = new HashSet<>();
        for (Field field : collectionAnnotation.type().getDeclaredFields()) {
            ExcelField excelField = field.getAnnotation(ExcelField.class);
            if (excelField != null) {
                int col = excelField.valueCol() >= 0 ? excelField.valueCol() : excelField.titleCol();
                columnsToCheck.add(col);
            }
        }
        
        if (columnsToCheck.isEmpty()) {
            return sheet.getLastRowNum(); // 如果没有字段注解，返回最后一行
        }
        
        int emptyRowCount = 0;
        for (int rowNum = collectionAnnotation.startRow(); rowNum <= sheet.getLastRowNum(); rowNum++) {
            Row row = sheet.getRow(rowNum);
            if (row == null) {
                emptyRowCount++;
                if (emptyRowCount >= maxEmptyRows) {
                    return rowNum - maxEmptyRows; // 返回连续空行前的最后一行
                }
                continue;
            }
            
            boolean hasData = false;
            for (int col : columnsToCheck) {
                Cell cell = row.getCell(col);
                if (cell != null && cell.getCellType() != CellType.BLANK) {
                    hasData = true;
                    break;
                }
            }
            
            if (hasData) {
                emptyRowCount = 0;
                endRow = rowNum;
            } else {
                emptyRowCount++;
                if (emptyRowCount >= maxEmptyRows) {
                    return endRow; // 返回最后有数据的行
                }
            }
        }
        
        return sheet.getLastRowNum();
    }

    /**
     * 单元格值转换
     * @param cell
     * @param targetType
     * @param dateFormat
     * @return
     */
    private Object convertCellValue(Cell cell, Class<?> targetType, String dateFormat) {
        switch (cell.getCellType()) {
            case STRING:
                return convertStringValue(cell.getStringCellValue().trim(), targetType, dateFormat);
            case NUMERIC:
                if (DateUtil.isCellDateFormatted(cell)) {
                    return cell.getDateCellValue();
                } else {
                    return convertNumericValue(cell.getNumericCellValue(), targetType);
                }
            case BOOLEAN:
                return cell.getBooleanCellValue();
            case FORMULA:
                try {
                    return convertStringValue(cell.getStringCellValue().trim(), targetType, dateFormat);
                } catch (Exception e) {
                    return cell.getCellFormula();
                }
            default:
                return null;
        }
    }
    
    private Object convertStringValue(String value, Class<?> targetType, String dateFormat) {
        if (value == null || value.isEmpty()) return null;
        
        if (targetType == String.class) {
            return value;
        } else if (targetType == Integer.class || targetType == int.class) {
            return Integer.parseInt(value);
        } else if (targetType == Long.class || targetType == long.class) {
            return Long.parseLong(value);
        } else if (targetType == Double.class || targetType == double.class) {
            return Double.parseDouble(value);
        } else if (targetType == BigDecimal.class) {
            return new BigDecimal(value);
        } else if (targetType == Date.class) {
            try {
                SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
                return sdf.parse(value);
            } catch (ParseException e) {
                log.warn("日期格式转换失败: {}", value);
                return null;
            }
        } else if (targetType == Boolean.class || targetType == boolean.class) {
            return "是".equals(value) || "YES".equalsIgnoreCase(value) || "TRUE".equalsIgnoreCase(value);
        }
        return value;
    }
    
    private Object convertNumericValue(double value, Class<?> targetType) {
        if (targetType == Integer.class || targetType == int.class) {
            return (int) value;
        } else if (targetType == Long.class || targetType == long.class) {
            return (long) value;
        } else if (targetType == Double.class || targetType == double.class) {
            return value;
        } else if (targetType == BigDecimal.class) {
            return BigDecimal.valueOf(value);
        } else if (targetType == Date.class) {
            return DateUtil.getJavaDate(value);
        }
        return value;
    }
    
    private boolean isRowEmpty(Row row) {
        for (Cell cell : row) {
            if (cell != null && cell.getCellType() != CellType.BLANK) {
                return false;
            }
        }
        return true;
    }
}
