package org.xyzh.common.utils.excel;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.xyzh.common.utils.validation.ValidationParam;
import org.xyzh.common.utils.validation.ValidationResult;
import org.xyzh.common.utils.validation.ValidationUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @description Excel读取工具类（非泛型版本）
 * @filename ExcelReaderUtils.java
 * @author yslg
 * @copyright xyzh
 * @since 2025-10-16
 */
public class ExcelReaderUtils {
    
    /**
     * @description 从文件读取Excel
     * @param file Excel文件
     * @param targetClass 目标对象Class
     * @param columnMappings Excel列映射配置列表
     * @return ExcelReadResult
     */
    public static ExcelReadResult<Object> readExcel(File file, Class<?> targetClass, List<ExcelColumnMapping> columnMappings) {
        try (FileInputStream fis = new FileInputStream(file)) {
            return readExcel(fis, file.getName(), targetClass, columnMappings, new HashMap<>());
        } catch (Exception e) {
            ExcelReadResult<Object> result = new ExcelReadResult<>();
            result.setSuccess(false);
            result.setErrorMessage("读取Excel文件失败: " + e.getMessage());
            return result;
        }
    }
    
    /**
     * @description 从文件读取Excel（带配置）
     * @param file Excel文件
     * @param targetClass 目标对象Class
     * @param columnMappings Excel列映射配置列表
     * @param options 配置选项
     * @return ExcelReadResult
     */
    public static ExcelReadResult<Object> readExcel(File file, Class<?> targetClass, 
                                                     List<ExcelColumnMapping> columnMappings, 
                                                     Map<String, Object> options) {
        try (FileInputStream fis = new FileInputStream(file)) {
            return readExcel(fis, file.getName(), targetClass, columnMappings, options);
        } catch (Exception e) {
            ExcelReadResult<Object> result = new ExcelReadResult<>();
            result.setSuccess(false);
            result.setErrorMessage("读取Excel文件失败: " + e.getMessage());
            return result;
        }
    }
    
    /**
     * @description 从输入流读取Excel
     * @param inputStream 输入流
     * @param fileName 文件名
     * @param targetClass 目标对象Class
     * @param columnMappings Excel列映射配置列表
     * @return ExcelReadResult
     */
    public static ExcelReadResult<Object> readExcel(InputStream inputStream, String fileName,
                                                     Class<?> targetClass, 
                                                     List<ExcelColumnMapping> columnMappings) {
        return readExcel(inputStream, fileName, targetClass, columnMappings, new HashMap<>());
    }
    
    /**
     * @description 从输入流读取Excel（带配置）
     * @param inputStream 输入流
     * @param fileName 文件名
     * @param targetClass 目标对象Class
     * @param columnMappings Excel列映射配置列表
     * @param options 配置选项（headerRowIndex, dataStartRowIndex, sheetIndex, sheetName, skipEmptyRow, maxRows, continueOnError）
     * @return ExcelReadResult
     */
    public static ExcelReadResult<Object> readExcel(InputStream inputStream, String fileName,
                                                     Class<?> targetClass, 
                                                     List<ExcelColumnMapping> columnMappings,
                                                     Map<String, Object> options) {
        ExcelReadResult<Object> result = new ExcelReadResult<>();
        
        try {
            // 获取配置
            int headerRowIndex = (int) options.getOrDefault("headerRowIndex", 0);
            int dataStartRowIndex = (int) options.getOrDefault("dataStartRowIndex", 1);
            int sheetIndex = (int) options.getOrDefault("sheetIndex", 0);
            String sheetName = (String) options.get("sheetName");
            boolean skipEmptyRow = (boolean) options.getOrDefault("skipEmptyRow", true);
            int maxRows = (int) options.getOrDefault("maxRows", 0);
            boolean continueOnError = (boolean) options.getOrDefault("continueOnError", true);
            
            // 创建Workbook
            Workbook workbook = createWorkbook(inputStream, fileName);
            
            // 获取Sheet
            Sheet sheet = getSheet(workbook, sheetIndex, sheetName);
            if (sheet == null) {
                result.setSuccess(false);
                result.setErrorMessage("未找到指定的Sheet");
                return result;
            }
            
            // 解析表头
            Map<String, Integer> headerMap = parseHeader(sheet, headerRowIndex);
            
            // 读取数据
            readData(sheet, headerMap, targetClass, columnMappings, dataStartRowIndex, 
                    skipEmptyRow, maxRows, continueOnError, result);
            
            workbook.close();
            
        } catch (Exception e) {
            result.setSuccess(false);
            result.setErrorMessage("读取Excel失败: " + e.getMessage());
        }
        
        return result;
    }
    
    /**
     * @description 创建Workbook对象
     */
    private static Workbook createWorkbook(InputStream inputStream, String fileName) throws Exception {
        if (fileName.endsWith(".xlsx")) {
            return new XSSFWorkbook(inputStream);
        } else if (fileName.endsWith(".xls")) {
            return new HSSFWorkbook(inputStream);
        } else {
            throw new IllegalArgumentException("不支持的文件格式，仅支持.xls和.xlsx");
        }
    }
    
    /**
     * @description 获取Sheet
     */
    private static Sheet getSheet(Workbook workbook, int sheetIndex, String sheetName) {
        if (sheetName != null && !sheetName.isEmpty()) {
            return workbook.getSheet(sheetName);
        } else {
            return workbook.getSheetAt(sheetIndex);
        }
    }
    
    /**
     * @description 解析表头
     */
    private static Map<String, Integer> parseHeader(Sheet sheet, int headerRowIndex) {
        Map<String, Integer> headerMap = new HashMap<>();
        Row headerRow = sheet.getRow(headerRowIndex);
        
        if (headerRow != null) {
            for (Cell cell : headerRow) {
                String headerName = getCellValue(cell).toString().trim();
                if (!headerName.isEmpty()) {
                    headerMap.put(headerName, cell.getColumnIndex());
                }
            }
        }
        
        return headerMap;
    }
    
    /**
     * @description 读取数据
     */
    private static void readData(Sheet sheet, Map<String, Integer> headerMap, 
                                 Class<?> targetClass, List<ExcelColumnMapping> columnMappings,
                                 int startRow, boolean skipEmptyRow, int maxRows, 
                                 boolean continueOnError, ExcelReadResult<Object> result) {
        int lastRowNum = sheet.getLastRowNum();
        int endRow = maxRows > 0 ? Math.min(startRow + maxRows, lastRowNum + 1) : lastRowNum + 1;
        
        for (int rowNum = startRow; rowNum < endRow; rowNum++) {
            Row row = sheet.getRow(rowNum);
            
            // 跳过空行
            if (skipEmptyRow && isEmptyRow(row)) {
                continue;
            }
            
            result.setTotalRows(result.getTotalRows() + 1);
            
            try {
                // 将行数据转换为对象
                Object data = convertRowToObject(row, headerMap, targetClass, columnMappings, rowNum + 1);
                
                // 数据校验
                List<ValidationParam> allValidations = new ArrayList<>();
                for (ExcelColumnMapping mapping : columnMappings) {
                    if (!mapping.getValidationParams().isEmpty()) {
                        allValidations.addAll(mapping.getValidationParams());
                    }
                }
                
                if (!allValidations.isEmpty()) {
                    ValidationResult validationResult = ValidationUtils.validate(data, allValidations);
                    if (!validationResult.isValid()) {
                        result.addError(rowNum + 1, validationResult.getFirstError());
                        if (!continueOnError) {
                            break;
                        }
                        continue;
                    }
                }
                
                result.addData(data);
                
            } catch (Exception e) {
                result.addError(rowNum + 1, e.getMessage());
                if (!continueOnError) {
                    break;
                }
            }
        }
    }
    
    /**
     * @description 判断是否为空行
     */
    private static boolean isEmptyRow(Row row) {
        if (row == null) {
            return true;
        }
        
        for (Cell cell : row) {
            if (cell != null && cell.getCellType() != CellType.BLANK) {
                String value = getCellValue(cell).toString().trim();
                if (!value.isEmpty()) {
                    return false;
                }
            }
        }
        
        return true;
    }
    
    /**
     * @description 将行数据转换为对象
     */
    private static Object convertRowToObject(Row row, Map<String, Integer> headerMap,
                                            Class<?> targetClass, List<ExcelColumnMapping> columnMappings,
                                            int rowNum) throws Exception {
        Object obj = targetClass.getDeclaredConstructor().newInstance();
        
        for (ExcelColumnMapping mapping : columnMappings) {
            // 获取单元格
            Cell cell = getCell(row, mapping, headerMap);
            
            // 获取单元格值
            Object cellValue = getCellValue(cell);
            
            // 处理空值
            if (cellValue == null || cellValue.toString().trim().isEmpty()) {
                if (mapping.isRequired()) {
                    throw new IllegalArgumentException("第" + rowNum + "行，字段[" + 
                            (mapping.getColumnName() != null ? mapping.getColumnName() : "索引" + mapping.getColumnIndex()) 
                            + "]不能为空");
                }
                // 使用默认值
                if (mapping.getDefaultValue() != null && !mapping.getDefaultValue().isEmpty()) {
                    cellValue = mapping.getDefaultValue();
                } else {
                    continue;
                }
            }
            
            // 类型转换
            Object fieldValue = convertValue(cellValue, mapping.getFieldType(), mapping.getDateFormat());
            
            // 设置字段值
            Field field = getField(targetClass, mapping.getFieldName());
            field.setAccessible(true);
            field.set(obj, fieldValue);
        }
        
        return obj;
    }
    
    /**
     * @description 获取字段（支持父类）
     */
    private static Field getField(Class<?> clazz, String fieldName) throws NoSuchFieldException {
        try {
            return clazz.getDeclaredField(fieldName);
        } catch (NoSuchFieldException e) {
            // 尝试从父类获取
            Class<?> superClass = clazz.getSuperclass();
            if (superClass != null) {
                return getField(superClass, fieldName);
            }
            throw e;
        }
    }
    
    /**
     * @description 获取单元格
     */
    private static Cell getCell(Row row, ExcelColumnMapping mapping, Map<String, Integer> headerMap) {
        if (row == null) {
            return null;
        }
        
        // 优先使用索引
        if (mapping.getColumnIndex() != null) {
            return row.getCell(mapping.getColumnIndex());
        }
        
        // 使用列名
        Integer columnIndex = headerMap.get(mapping.getColumnName());
        if (columnIndex != null) {
            return row.getCell(columnIndex);
        }
        
        return null;
    }
    
    /**
     * @description 获取单元格值
     */
    private static Object getCellValue(Cell cell) {
        if (cell == null) {
            return null;
        }
        
        switch (cell.getCellType()) {
            case STRING:
                return cell.getStringCellValue();
            case NUMERIC:
                if (DateUtil.isCellDateFormatted(cell)) {
                    return cell.getDateCellValue();
                } else {
                    return cell.getNumericCellValue();
                }
            case BOOLEAN:
                return cell.getBooleanCellValue();
            case FORMULA:
                return cell.getCellFormula();
            case BLANK:
                return "";
            default:
                return cell.toString();
        }
    }
    
    /**
     * @description 类型转换
     */
    private static Object convertValue(Object value, Class<?> targetType, String dateFormat) throws Exception {
        if (value == null) {
            return null;
        }
        
        String strValue = value.toString().trim();
        
        // String类型
        if (targetType == String.class) {
            return strValue;
        }
        
        // Integer类型
        if (targetType == Integer.class || targetType == int.class) {
            if (value instanceof Number) {
                return ((Number) value).intValue();
            }
            return Integer.parseInt(strValue);
        }
        
        // Long类型
        if (targetType == Long.class || targetType == long.class) {
            if (value instanceof Number) {
                return ((Number) value).longValue();
            }
            return Long.parseLong(strValue);
        }
        
        // Double类型
        if (targetType == Double.class || targetType == double.class) {
            if (value instanceof Number) {
                return ((Number) value).doubleValue();
            }
            return Double.parseDouble(strValue);
        }
        
        // Float类型
        if (targetType == Float.class || targetType == float.class) {
            if (value instanceof Number) {
                return ((Number) value).floatValue();
            }
            return Float.parseFloat(strValue);
        }
        
        // Boolean类型
        if (targetType == Boolean.class || targetType == boolean.class) {
            if (value instanceof Boolean) {
                return value;
            }
            return Boolean.parseBoolean(strValue) || "1".equals(strValue) || 
                   "是".equals(strValue) || "true".equalsIgnoreCase(strValue);
        }
        
        // Date类型
        if (targetType == Date.class) {
            if (value instanceof Date) {
                return value;
            }
            SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
            return sdf.parse(strValue);
        }
        
        // 其他类型
        return value;
    }
}

