package com.erp.dataimport.service.impl;

import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.erp.common.core.model.PageResponse;
import com.erp.dataimport.dto.*;
import com.erp.dataimport.entity.ImportRecord;
import com.erp.dataimport.entity.ImportTask;
import com.erp.dataimport.entity.ImportTemplate;
import com.erp.dataimport.exception.DataImportException;
import com.erp.dataimport.repository.ImportRecordRepository;
import com.erp.dataimport.repository.ImportTaskRepository;
import com.erp.dataimport.repository.ImportTemplateRepository;
import com.erp.dataimport.service.DataImportService;
import com.erp.dataimport.util.CsvUtils;
import com.erp.dataimport.util.ExcelUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * 数据导入服务实现
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class DataImportServiceImpl implements DataImportService {

    private final ImportTaskRepository importTaskRepository;
    private final ImportRecordRepository importRecordRepository;
    private final ImportTemplateRepository importTemplateRepository;
    private final RedisTemplate<String, Object> redisTemplate;
    private final ObjectMapper objectMapper;

    @Value("${service.import-export.temp-dir:/tmp/import-export}")
    private String tempDir;

    @Value("${service.import-export.batch-size:1000}")
    private int batchSize;

    @Value("${service.import-export.max-excel-rows:100000}")
    private int maxExcelRows;

    // 支持的业务类型
    private static final Set<String> SUPPORTED_BIZ_TYPES = new LinkedHashSet<>(Arrays.asList(
            "goods", "customer", "supplier", "order", "inventory", "employee", "warehouse"
    ));

    @Override
    @Async
    public CompletableFuture<ImportResultResponse> importFile(MultipartFile file, ImportFileRequest request) {
        return CompletableFuture.supplyAsync(() -> importFileSync(file, request));
    }

    @Override
    @Transactional
    public ImportResultResponse importFileSync(MultipartFile file, ImportFileRequest request) {
        String originalFileName = file.getOriginalFilename();
        if (originalFileName == null || originalFileName.isEmpty()) {
            throw new DataImportException("文件名不能为空");
        }

        // 保存文件
        String filePath = saveFile(file);
        String fileFormat = getFileFormat(originalFileName);

        // 创建导入任务
        ImportTask task = new ImportTask();
        task.setTaskName(request.getTaskName());
        task.setBizType(request.getBizType());
        task.setFileFormat(fileFormat);
        task.setOriginalFileName(originalFileName);
        task.setFilePath(filePath);
        task.setFileSize(file.getSize());
        task.setStatus("pending");
        task.setTenantId(request.getTenantId());
        task.setCreatorId(request.getCreatorId());
        task.setCreatorName(request.getCreatorName());
        task.setCreatedAt(LocalDateTime.now());
        importTaskRepository.insert(task);

        // 更新任务状态为处理中
        task.setStatus("processing");
        importTaskRepository.updateById(task);

        try {
            // 读取文件数据
            List<Map<Integer, String>> dataList;
            int totalRows;
            
            if ("csv".equalsIgnoreCase(fileFormat)) {
                try (InputStream inputStream = new FileInputStream(filePath)) {
                    dataList = CsvUtils.readCsvWithIndex(inputStream, 0);
                }
            } else {
                try (InputStream inputStream = new FileInputStream(filePath)) {
                    dataList = ExcelUtils.readExcel(inputStream, originalFileName, 0);
                }
            }

            // 移除表头
            if (!dataList.isEmpty()) {
                dataList.remove(0);
            }

            totalRows = dataList.size();
            task.setTotalRows(totalRows);
            importTaskRepository.updateById(task);

            // 验证数据量
            if (totalRows > maxExcelRows) {
                throw new DataImportException("数据量超出限制，最大支持" + maxExcelRows + "行");
            }

            // 处理数据
            int successRows = 0;
            int failRows = 0;
            int skipRows = 0;
            List<String> errorSummary = new ArrayList<>();

            for (int i = 0; i < dataList.size(); i++) {
                Map<Integer, String> rowData = dataList.get(i);
                int rowNumber = i + 2; // 行号从2开始（1是表头）

                try {
                    // 验证数据
                    validateRowData(rowData, request.getBizType());

                    // 转换为JSON并存储记录
                    ImportRecord record = new ImportRecord();
                    record.setTaskId(task.getId());
                    record.setRowNumber(rowNumber);
                    record.setOriginalData(toJson(rowData));
                    record.setResult("success");
                    record.setTenantId(request.getTenantId());
                    record.setCreatedAt(LocalDateTime.now());
                    importRecordRepository.insert(record);

                    // 实际业务处理（这里简化处理）
                    processBusinessData(rowData, request.getBizType(), request.getTenantId());

                    successRows++;
                } catch (DataImportException e) {
                    failRows++;
                    errorSummary.add("第" + rowNumber + "行: " + e.getMessage());

                    ImportRecord record = new ImportRecord();
                    record.setTaskId(task.getId());
                    record.setRowNumber(rowNumber);
                    record.setOriginalData(toJson(rowData));
                    record.setResult("fail");
                    record.setErrorMessage(e.getMessage());
                    record.setErrorField(e.getErrorField());
                    record.setTenantId(request.getTenantId());
                    record.setCreatedAt(LocalDateTime.now());
                    importRecordRepository.insert(record);
                } catch (Exception e) {
                    failRows++;
                    errorSummary.add("第" + rowNumber + "行: " + e.getMessage());

                    ImportRecord record = new ImportRecord();
                    record.setTaskId(task.getId());
                    record.setRowNumber(rowNumber);
                    record.setOriginalData(toJson(rowData));
                    record.setResult("fail");
                    record.setErrorMessage(e.getMessage());
                    record.setTenantId(request.getTenantId());
                    record.setCreatedAt(LocalDateTime.now());
                    importRecordRepository.insert(record);
                }
            }

            // 更新任务结果
            task.setSuccessRows(successRows);
            task.setFailRows(failRows);
            task.setSkipRows(skipRows);
            task.setFinishTime(LocalDateTime.now());

            if (failRows == 0) {
                task.setStatus("completed");
            } else if (successRows == 0) {
                task.setStatus("failed");
            } else {
                task.setStatus("partial");
            }

            if (!errorSummary.isEmpty()) {
                task.setErrorSummary(String.join("; ", errorSummary.stream().limit(10).collect(Collectors.toList())));
                if (errorSummary.size() > 10) {
                    task.setErrorSummary(task.getErrorSummary() + "...");
                }
            }

            importTaskRepository.updateById(task);

            return buildImportResultResponse(task);

        } catch (DataImportException e) {
            task.setStatus("failed");
            task.setErrorSummary(e.getMessage());
            task.setFinishTime(LocalDateTime.now());
            importTaskRepository.updateById(task);
            throw e;
        } catch (Exception e) {
            log.error("导入失败", e);
            task.setStatus("failed");
            task.setErrorSummary(e.getMessage());
            task.setFinishTime(LocalDateTime.now());
            importTaskRepository.updateById(task);
            throw new DataImportException("IMPORT_FAILED", "导入失败: " + e.getMessage());
        }
    }

    @Override
    public ImportTaskPageResponse listImportTasks(ImportTaskListRequest request) {
        LambdaQueryWrapper<ImportTask> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(request.getTenantId() != null, ImportTask::getTenantId, request.getTenantId());
        wrapper.eq(request.getBizType() != null, ImportTask::getBizType, request.getBizType());
        wrapper.eq(request.getStatus() != null, ImportTask::getStatus, request.getStatus());
        wrapper.like(request.getKeyword() != null, ImportTask::getTaskName, request.getKeyword());
        wrapper.orderByDesc(ImportTask::getCreatedAt);

        IPage<ImportTask> page = new Page<>(request.getPage(), request.getLimit());
        IPage<ImportTask> result = importTaskRepository.selectPage(page, wrapper);

        List<ImportTaskDTO> records = result.getRecords().stream()
                .map(this::toTaskDTO)
                .collect(Collectors.toList());

        return ImportTaskPageResponse.builder()
                .total(result.getTotal())
                .page(request.getPage())
                .limit(request.getLimit())
                .totalPages((int) result.getPages())
                .records(records)
                .build();
    }

    @Override
    public ImportTaskDTO getImportTask(Long taskId, Long tenantId) {
        ImportTask task = importTaskRepository.selectByIdAndTenant(taskId, tenantId);
        if (task == null) {
            throw new DataImportException("TASK_NOT_FOUND", "导入任务不存在");
        }
        return toTaskDTO(task);
    }

    @Override
    public ImportResultResponse getImportResult(Long taskId, Long tenantId) {
        ImportTask task = importTaskRepository.selectByIdAndTenant(taskId, tenantId);
        if (task == null) {
            throw new DataImportException("TASK_NOT_FOUND", "导入任务不存在");
        }
        return buildImportResultResponse(task);
    }

    @Override
    public ImportRecordPageResponse listImportFailRecords(ImportRecordListRequest request) {
        LambdaQueryWrapper<ImportRecord> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ImportRecord::getTaskId, request.getTaskId());
        wrapper.eq(request.getResult() != null, ImportRecord::getResult, request.getResult());

        IPage<ImportRecord> page = new Page<>(request.getPage(), request.getLimit());
        IPage<ImportRecord> result = importRecordRepository.selectPage(page, wrapper);

        List<ImportRecordDTO> records = result.getRecords().stream()
                .map(this::toRecordDTO)
                .collect(Collectors.toList());

        return ImportRecordPageResponse.builder()
                .total(result.getTotal())
                .page(request.getPage())
                .limit(request.getLimit())
                .totalPages((int) result.getPages())
                .records(records)
                .build();
    }

    @Override
    public void downloadErrorReport(Long taskId, Long tenantId, OutputStream outputStream) {
        ImportTask task = importTaskRepository.selectByIdAndTenant(taskId, tenantId);
        if (task == null) {
            throw new DataImportException("TASK_NOT_FOUND", "导入任务不存在");
        }

        List<ImportRecord> failRecords = importRecordRepository.selectFailRecordsByTaskId(taskId);

        List<String> headers = Arrays.asList("行号", "原始数据", "错误信息", "错误字段");
        List<List<Object>> dataList = new ArrayList<>();

        for (ImportRecord record : failRecords) {
            dataList.add(Arrays.asList(
                    record.getRowNumber(),
                    record.getOriginalData(),
                    record.getErrorMessage(),
                    record.getErrorField()
            ));
        }

        ExcelUtils.generateExcel(outputStream, "错误报告", headers, dataList);
    }

    @Override
    @Transactional
    public void deleteImportTask(Long taskId, Long tenantId) {
        ImportTask task = importTaskRepository.selectByIdAndTenant(taskId, tenantId);
        if (task == null) {
            throw new DataImportException("TASK_NOT_FOUND", "导入任务不存在");
        }

        // 删除关联记录
        LambdaQueryWrapper<ImportRecord> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ImportRecord::getTaskId, taskId);
        importRecordRepository.delete(wrapper);

        // 删除任务
        importTaskRepository.deleteById(taskId);

        // 删除文件
        if (task.getFilePath() != null) {
            try {
                Files.deleteIfExists(Paths.get(task.getFilePath()));
            } catch (IOException e) {
                log.warn("删除文件失败: {}", task.getFilePath());
            }
        }
    }

    @Override
    public void generateTemplate(String bizType, Long tenantId, OutputStream outputStream) {
        if (!SUPPORTED_BIZ_TYPES.contains(bizType)) {
            throw new DataImportException("UNSUPPORTED_BIZ_TYPE", "不支持的业务类型: " + bizType);
        }

        List<String> headers = getHeadersByBizType(bizType);
        List<List<Object>> sampleData = getSampleDataByBizType(bizType);

        ExcelUtils.generateTemplate(outputStream, getSheetNameByBizType(bizType), headers, sampleData);
    }

    @Override
    @Transactional
    public ImportTemplateDTO createTemplate(CreateTemplateRequest request) {
        // 检查模板编码是否重复
        ImportTemplate existTemplate = importTemplateRepository.selectByCodeAndBizType(
                request.getTemplateCode(), request.getBizType(), request.getTenantId());
        if (existTemplate != null) {
            throw new DataImportException("TEMPLATE_EXISTS", "模板编码已存在");
        }

        ImportTemplate template = new ImportTemplate();
        template.setTemplateName(request.getTemplateName());
        template.setTemplateCode(request.getTemplateCode());
        template.setBizType(request.getBizType());
        template.setDescription(request.getDescription());
        template.setColumnDefinition(toJson(request.getColumns()));
        template.setIsDefault(request.getIsDefault());
        template.setTenantId(request.getTenantId());
        template.setCreatorId(request.getCreatorId());
        template.setCreatorName(request.getCreatorName());
        template.setCreatedAt(LocalDateTime.now());
        template.setUpdatedAt(LocalDateTime.now());

        importTemplateRepository.insert(template);

        return toTemplateDTO(template);
    }

    @Override
    public List<ImportTemplateDTO> listTemplates(String bizType, Long tenantId) {
        LambdaQueryWrapper<ImportTemplate> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ImportTemplate::getTenantId, tenantId);
        wrapper.eq(bizType != null, ImportTemplate::getBizType, bizType);
        wrapper.orderByDesc(ImportTemplate::getIsDefault).orderByDesc(ImportTemplate::getCreatedAt);

        List<ImportTemplate> templates = importTemplateRepository.selectList(wrapper);
        return templates.stream().map(this::toTemplateDTO).collect(Collectors.toList());
    }

    @Override
    @Transactional
    public void deleteTemplate(Long templateId, Long tenantId) {
        ImportTemplate template = importTemplateRepository.selectById(templateId);
        if (template == null || !template.getTenantId().equals(tenantId)) {
            throw new DataImportException("TEMPLATE_NOT_FOUND", "模板不存在");
        }
        importTemplateRepository.deleteById(templateId);
    }

    @Override
    public void exportToCsv(String bizType, List<String> columns, List<List<Object>> data, OutputStream outputStream) {
        CsvUtils.writeCsv(outputStream, columns, data);
    }

    @Override
    public void exportToExcel(String bizType, List<String> headers, List<List<Object>> data, OutputStream outputStream) {
        ExcelUtils.generateExcel(outputStream, getSheetNameByBizType(bizType), headers, data);
    }

    @Override
    public List<String> getSupportedBizTypes() {
        return new ArrayList<>(SUPPORTED_BIZ_TYPES);
    }

    // ==================== 私有方法 ====================

    private String saveFile(MultipartFile file) {
        try {
            Path tempPath = Paths.get(tempDir);
            if (!Files.exists(tempPath)) {
                Files.createDirectories(tempPath);
            }

            String fileName = UUID.randomUUID().toString() + "_" + file.getOriginalFilename();
            Path targetPath = tempPath.resolve(fileName);
            file.transferTo(targetPath);

            return targetPath.toString();
        } catch (IOException e) {
            log.error("保存文件失败", e);
            throw new DataImportException("FILE_SAVE_ERROR", "保存文件失败");
        }
    }

    private String getFileFormat(String fileName) {
        String ext = FilenameUtils.getExtension(fileName).toLowerCase();
        if ("xlsx".equals(ext) || "xls".equals(ext)) {
            return "excel";
        } else if ("csv".equals(ext)) {
            return "csv";
        }
        return ext;
    }

    private void validateRowData(Map<Integer, String> rowData, String bizType) {
        if (rowData == null || rowData.isEmpty()) {
            throw new DataImportException("VALIDATION_ERROR", "数据不能为空", null);
        }
        // 根据业务类型添加具体的验证逻辑
        // 这里简化处理，实际应该根据bizType调用不同的验证器
    }

    private void processBusinessData(Map<Integer, String> rowData, String bizType, Long tenantId) {
        // 这里应该是调用具体业务服务的逻辑
        // 目前只是模拟处理
        log.debug("处理业务数据: bizType={}, tenantId={}, rowData={}", bizType, tenantId, rowData);
    }

    private ImportResultResponse buildImportResultResponse(ImportTask task) {
        return ImportResultResponse.builder()
                .taskId(task.getId())
                .totalRows(task.getTotalRows())
                .successRows(task.getSuccessRows())
                .failRows(task.getFailRows())
                .skipRows(task.getSkipRows())
                .successRate(task.getSuccessRate())
                .status(task.getStatus())
                .statusLabel(getStatusLabel(task.getStatus()))
                .errorSummary(task.getErrorSummary())
                .build();
    }

    private String getStatusLabel(String status) {
        switch (status) {
            case "pending": return "待处理";
            case "processing": return "处理中";
            case "completed": return "已完成";
            case "failed": return "失败";
            case "partial": return "部分成功";
            default: return status;
        }
    }

    private ImportTaskDTO toTaskDTO(ImportTask task) {
        return ImportTaskDTO.builder()
                .id(task.getId())
                .taskName(task.getTaskName())
                .bizType(task.getBizType())
                .bizTypeLabel(getBizTypeLabel(task.getBizType()))
                .fileFormat(task.getFileFormat())
                .originalFileName(task.getOriginalFileName())
                .fileSize(task.getFileSize())
                .totalRows(task.getTotalRows())
                .successRows(task.getSuccessRows())
                .failRows(task.getFailRows())
                .skipRows(task.getSkipRows())
                .status(task.getStatus())
                .statusLabel(getStatusLabel(task.getStatus()))
                .tenantId(task.getTenantId())
                .creatorId(task.getCreatorId())
                .creatorName(task.getCreatorName())
                .finishTime(task.getFinishTime())
                .errorSummary(task.getErrorSummary())
                .createdAt(task.getCreatedAt())
                .updatedAt(task.getUpdatedAt())
                .successRate(task.getSuccessRate())
                .build();
    }

    private ImportRecordDTO toRecordDTO(ImportRecord record) {
        return ImportRecordDTO.builder()
                .id(record.getId())
                .taskId(record.getTaskId())
                .rowNumber(record.getRowNumber())
                .originalData(record.getOriginalData())
                .processedData(record.getProcessedData())
                .targetId(record.getTargetId())
                .result(record.getResult())
                .resultLabel(getResultLabel(record.getResult()))
                .errorMessage(record.getErrorMessage())
                .errorField(record.getErrorField())
                .build();
    }

    private ImportTemplateDTO toTemplateDTO(ImportTemplate template) {
        List<ImportTemplateDTO.ColumnDefinition> columns = null;
        if (template.getColumnDefinition() != null) {
            try {
                columns = objectMapper.readValue(template.getColumnDefinition(),
                        objectMapper.getTypeFactory().constructCollectionType(List.class, ImportTemplateDTO.ColumnDefinition.class));
            } catch (Exception e) {
                log.warn("解析列定义失败", e);
            }
        }

        return ImportTemplateDTO.builder()
                .id(template.getId())
                .templateName(template.getTemplateName())
                .templateCode(template.getTemplateCode())
                .bizType(template.getBizType())
                .bizTypeLabel(getBizTypeLabel(template.getBizType()))
                .description(template.getDescription())
                .filePath(template.getFilePath())
                .columns(columns)
                .isDefault(template.getIsDefault())
                .creatorId(template.getCreatorId())
                .creatorName(template.getCreatorName())
                .createdAt(template.getCreatedAt())
                .updatedAt(template.getUpdatedAt())
                .build();
    }

    private String getBizTypeLabel(String bizType) {
        switch (bizType) {
            case "goods": return "商品";
            case "customer": return "客户";
            case "supplier": return "供应商";
            case "order": return "订单";
            case "inventory": return "库存";
            case "employee": return "员工";
            case "warehouse": return "仓库";
            default: return bizType;
        }
    }

    private String getResultLabel(String result) {
        switch (result) {
            case "success": return "成功";
            case "fail": return "失败";
            case "skip": return "跳过";
            default: return result;
        }
    }

    private String getSheetNameByBizType(String bizType) {
        return getBizTypeLabel(bizType) + "数据";
    }

    private List<String> getHeadersByBizType(String bizType) {
        switch (bizType) {
            case "goods":
                return Arrays.asList("商品名称", "商品编码", "条形码", "商品分类", "单位", "零售价", "成本价");
            case "customer":
                return Arrays.asList("客户名称", "联系人", "联系电话", "地址", "邮箱");
            case "supplier":
                return Arrays.asList("供应商名称", "联系人", "联系电话", "地址", "邮箱");
            case "order":
                return Arrays.asList("订单编号", "客户名称", "商品名称", "数量", "单价", "总价");
            case "inventory":
                return Arrays.asList("仓库名称", "商品名称", "商品编码", "库存数量", "预警值");
            default:
                return Arrays.asList("数据项1", "数据项2", "数据项3", "数据项4", "数据项5");
        }
    }

    private List<List<Object>> getSampleDataByBizType(String bizType) {
        List<List<Object>> sampleData = new ArrayList<>();
        // 添加2行示例数据
        switch (bizType) {
            case "goods":
                sampleData.add(Arrays.asList("示例商品1", "G001", "6901234567890", "电子产品", "个", "99.99", "50.00"));
                sampleData.add(Arrays.asList("示例商品2", "G002", "6901234567891", "办公用品", "箱", "199.99", "120.00"));
                break;
            case "customer":
                sampleData.add(Arrays.asList("示例客户1", "张三", "13800138000", "北京市朝阳区", "zhangsan@example.com"));
                sampleData.add(Arrays.asList("示例客户2", "李四", "13900139000", "上海市浦东新区", "lisi@example.com"));
                break;
            case "supplier":
                sampleData.add(Arrays.asList("示例供应商1", "王五", "13700137000", "广州市天河区", "wangwu@example.com"));
                sampleData.add(Arrays.asList("示例供应商2", "赵六", "13600136000", "深圳市南山区", "zhaoliu@example.com"));
                break;
            default:
                sampleData.add(Arrays.asList("示例数据1", "值1", "值2", "值3", "值4"));
                sampleData.add(Arrays.asList("示例数据2", "值5", "值6", "值7", "值8"));
        }
        return sampleData;
    }

    private String toJson(Object obj) {
        try {
            return objectMapper.writeValueAsString(obj);
        } catch (Exception e) {
            return "{}";
        }
    }
}
