package com.fuyuanshen.equipment.excel;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.fastjson2.JSON;
import com.fuyuanshen.common.core.utils.file.ImageCompressUtil;
import com.fuyuanshen.equipment.constants.DeviceConstants;
import com.fuyuanshen.equipment.domain.Device;
import com.fuyuanshen.equipment.domain.DeviceType;
import com.fuyuanshen.equipment.domain.dto.DeviceExcelImportDTO;
import com.fuyuanshen.equipment.domain.dto.ImportResult;
import com.fuyuanshen.equipment.domain.form.DeviceForm;
import com.fuyuanshen.equipment.domain.form.DeviceTypeForm;
import com.fuyuanshen.equipment.handler.ImageWriteHandler;
import com.fuyuanshen.system.domain.vo.SysOssVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.util.ZipSecureFile;
import org.apache.poi.xssf.usermodel.*;

import java.io.File;
import java.util.*;


@Slf4j
public class UploadDeviceDataListener implements ReadListener<DeviceExcelImportDTO> {

    // 存储图片数据的映射
    private Map<Integer, byte[]> rowImageMap = new HashMap<>();

    private DeviceImportParams params;

    private Map<Integer, Device> rowDeviceMap = new HashMap<>();
    private Map<Integer, DeviceExcelImportDTO> rowDtoMap = new HashMap<>();
    private List<Integer> rowIndexList = new ArrayList<>();

    private int successCount = 0;
    private int failureCount = 0;
    private final List<DeviceExcelImportDTO> failedRecords = new ArrayList<>();


    public UploadDeviceDataListener(DeviceImportParams params) {
        this.params = params;
    }


    public ImportResult getImportResult1() {
        ImportResult result = new ImportResult();
        result.setSuccessCount(successCount);
        result.setFailureCount(failureCount);

        // 准备失败记录
        List<DeviceExcelImportDTO> failedRecordsWithImages = new ArrayList<>();

        // 创建一个映射，用于存储失败记录行号与图片数据的关系
        Map<Integer, byte[]> errorReportImageMap = new HashMap<>();

        for (int i = 0; i < failedRecords.size(); i++) {
            DeviceExcelImportDTO failedRecord = failedRecords.get(i);
            // 创建副本，避免修改原始数据
            DeviceExcelImportDTO recordWithImage = new DeviceExcelImportDTO();
            BeanUtil.copyProperties(failedRecord, recordWithImage);
            // 设置图片占位符，让用户知道这里有图片
            // recordWithImage.setDevicePic("[图片]");
            failedRecordsWithImages.add(recordWithImage);

            // 获取原始行号
            Integer originalRowIndex = null;
            for (Map.Entry<Integer, DeviceExcelImportDTO> entry : rowDtoMap.entrySet()) {
                if (entry.getValue() == failedRecord) {
                    originalRowIndex = entry.getKey();
                    break;
                }
            }

            // 保存图片数据用于错误报告
            if (originalRowIndex != null) {
                byte[] imageData = rowImageMap.get(originalRowIndex);
                if (imageData != null) {
                    errorReportImageMap.put(i, imageData); // 使用新的列表索引
                }
            }
        }

        result.setFailedRecords(failedRecordsWithImages);

        // 生成错误报告
        if (!failedRecordsWithImages.isEmpty()) {
            try {
                // 生成唯一的文件名
                String fileName = "import_errors_" + System.currentTimeMillis() + ".xlsx";

                // 创建错误报告目录
                String errorDirPath = params.getFilePath() + DeviceConstants.ERROR_REPORT_DIR;
                File errorDir = new File(errorDirPath);
                if (!errorDir.exists() && !errorDir.mkdirs()) {
                    log.error("无法创建错误报告目录: {}", errorDirPath);
                    return result;
                }

                // 保存错误报告到文件（包含图片）
                File errorFile = new File(errorDir, fileName);
                EasyExcel.write(errorFile, DeviceExcelImportDTO.class)
                        .registerWriteHandler(new ImageWriteHandler(errorReportImageMap)) // 传递图片数据映射
                        .sheet("失败数据").doWrite(failedRecordsWithImages);

                // 生成访问URL
                SysOssVo upload = params.getOssService().upload(errorFile);
                result.setErrorExcelUrl(upload.getUrl());
                log.info("错误报告已保存: {}", errorFile.getAbsolutePath());
            } catch (Exception e) {
                log.error("生成错误报告失败", e);
            }
        }

        return result;
    }

    public ImportResult getImportResult() {
        ImportResult result = new ImportResult();
        result.setSuccessCount(successCount);
        result.setFailureCount(failureCount);

        // 准备失败记录
        List<DeviceExcelImportDTO> failedRecordsWithImages = new ArrayList<>();

        for (int i = 0; i < failedRecords.size(); i++) {
            DeviceExcelImportDTO failedRecord = failedRecords.get(i);
            // 创建副本，避免修改原始数据
            DeviceExcelImportDTO recordWithImage = new DeviceExcelImportDTO();
            BeanUtil.copyProperties(failedRecord, recordWithImage);

            // 获取原始行号
            Integer originalRowIndex = null;
            for (Map.Entry<Integer, DeviceExcelImportDTO> entry : rowDtoMap.entrySet()) {
                if (entry.getValue() == failedRecord) {
                    originalRowIndex = entry.getKey();
                    break;
                }
            }

            // 保存图片数据用于错误报告
            if (originalRowIndex != null) {
                byte[] imageData = rowImageMap.get(originalRowIndex);
                if (imageData != null) {
                    // recordWithImage.setImageData(imageData);
                    recordWithImage.setDevicePic(imageData);
                }
            }

            failedRecordsWithImages.add(recordWithImage);
        }

        result.setFailedRecords(failedRecordsWithImages);

        // 生成错误报告
        if (!failedRecordsWithImages.isEmpty()) {
            try {
                // 生成唯一的文件名
                String fileName = "import_errors_" + System.currentTimeMillis() + ".xlsx";

                // 创建错误报告目录
                String errorDirPath = params.getFilePath() + DeviceConstants.ERROR_REPORT_DIR;
                File errorDir = new File(errorDirPath);
                if (!errorDir.exists() && !errorDir.mkdirs()) {
                    log.error("无法创建错误报告目录: {}", errorDirPath);
                    return result;
                }

                // 保存错误报告到文件（包含图片）
                File errorFile = new File(errorDir, fileName);
                EasyExcel.write(errorFile, DeviceExcelImportDTO.class)
                        .sheet("失败数据").doWrite(failedRecordsWithImages);

                // 生成访问URL
                SysOssVo upload = params.getOssService().upload(errorFile);
                String url = upload.getUrl();
                // 将http://替换为https://，但不影响已经是https://的URL
                if (url.startsWith("http://")) {
                    url = "https://" + url.substring(7);
                }
                result.setErrorExcelUrl(url);
                log.info("错误报告已保存: {}", errorFile.getAbsolutePath());
                log.info("错误报告已保存: {}", url);
            } catch (Exception e) {
                log.error("生成错误报告失败", e);
            }
        }

        return result;
    }

    @Override
    public void invoke(DeviceExcelImportDTO data, AnalysisContext context) {
        log.info("解析到一条数据: {}", JSON.toJSONString(data));
        int rowIndex = context.readRowHolder().getRowIndex();

        Device device = new Device();
        BeanUtil.copyProperties(data, device, true);
        rowDeviceMap.put(rowIndex, device);
        rowDtoMap.put(rowIndex, data);
        rowIndexList.add(rowIndex);
    }


    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        try {
            processImages();
            processDataRowByRow();
            log.info("数据处理完成！成功：{}条，失败：{}条", successCount, failureCount);
        } catch (Exception e) {
            log.error("数据处理失败：{}", e.getMessage(), e);
            throw new RuntimeException("导入失败", e);
        }
    }


    private void processDataRowByRow() {
        // 如果没有数据，直接返回
        if (rowIndexList.isEmpty()) {
            return;
        }

        // 批量处理设备类型，减少数据库查询次数
        Set<String> typeNames = new HashSet<>();
        for (Integer rowIndex : rowIndexList) {
            Device device = rowDeviceMap.get(rowIndex);
            if (device != null && device.getTypeName() != null) {
                typeNames.add(device.getTypeName());
            }
        }

        // 批量查询所有设备类型
        Map<String, DeviceType> deviceTypeMap = new HashMap<>();
        if (!typeNames.isEmpty()) {
            List<DeviceType> deviceTypes = params.getDeviceTypeService().queryByNames(new ArrayList<>(typeNames));
            for (DeviceType deviceType : deviceTypes) {
                deviceTypeMap.put(deviceType.getTypeName(), deviceType);
            }
        }

        for (Integer rowIndex : rowIndexList) {
            Device device = rowDeviceMap.get(rowIndex);
            DeviceExcelImportDTO originalDto = rowDtoMap.get(rowIndex);
            try {
                // 从缓存中获取设备类型
                DeviceType deviceType = deviceTypeMap.get(device.getTypeName());

                DeviceForm deviceForm = new DeviceForm();
                deviceForm.setDeviceName(device.getDeviceName());
                deviceForm.setDeviceType(deviceType != null ? deviceType.getId() : null);
                deviceForm.setTypeName(device.getTypeName());
                deviceForm.setRemark(device.getRemark());
                deviceForm.setDeviceMac(device.getDeviceMac());
                deviceForm.setDeviceImei(device.getDeviceImei());
                deviceForm.setBluetoothName(device.getBluetoothName());
                deviceForm.setDevicePic(device.getDevicePic());

                // 设置设备类型相关信息，供设备服务内部创建设备类型时使用
                if (deviceType == null) {
                    deviceForm.setIsSupportBle(originalDto.getIsSupportBle());
                    deviceForm.setLocateMode(originalDto.getLocateMode());
                    deviceForm.setCommunicationMode(originalDto.getCommunicationMode());
                    deviceForm.setAppModelDictionary(originalDto.getAppModelDictionary());
                    deviceForm.setPcModelDictionary(originalDto.getPcModelDictionary());
                }

                params.getDeviceService().addDevice(deviceForm);
                successCount++;
                log.info("行 {} 数据插入成功", rowIndex);
            } catch (Exception e) {
                failureCount++;
                originalDto.setErrorMessage(e.getMessage());
                // originalDto.setErrorMessage("数据有误，请核对模板后，确认数据无误后，重新再试！！！");
                failedRecords.add(originalDto);
                log.error("行 {} 数据插入失败: {}", rowIndex, e.getMessage());
            }
        }
    }

    /**
     * 处理图片数据
     */
    private void processImages() {
        // 如果没有数据行，直接返回
        if (rowIndexList.isEmpty()) {
            return;
        }

        // 检查是否有图片需要处理
        try {
            // 只在确实有图片时才打开文件处理
            boolean hasImages = false;
            try (OPCPackage opcPackage = OPCPackage.open(params.getFile().getInputStream())) {
                ZipSecureFile.setMinInflateRatio(-1.0d);
                XSSFWorkbook workbook = new XSSFWorkbook(opcPackage);
                XSSFSheet sheet = workbook.getSheetAt(0);

                XSSFDrawing drawing = sheet.getDrawingPatriarch();
                if (drawing != null) {
                    for (XSSFShape shape : drawing.getShapes()) {
                        if (shape instanceof XSSFPicture) {
                            hasImages = true;
                            break;
                        }
                    }
                }
            } catch (Exception e) {
                log.warn("检查图片时发生异常: {}", e.getMessage());
                // 如果检查图片失败，继续处理数据
                return;
            }

            // 如果没有图片，直接返回
            if (!hasImages) {
                log.info("未检测到图片，跳过图片处理");
                return;
            }

            // 有图片时才进行处理
            try (OPCPackage opcPackage = OPCPackage.open(params.getFile().getInputStream())) {
                ZipSecureFile.setMinInflateRatio(-1.0d);
                XSSFWorkbook workbook = new XSSFWorkbook(opcPackage);
                XSSFSheet sheet = workbook.getSheetAt(0);

                XSSFDrawing drawing = sheet.getDrawingPatriarch();
                if (drawing == null) return;

                for (XSSFShape shape : drawing.getShapes()) {
                    if (shape instanceof XSSFPicture) {
                        XSSFPicture picture = (XSSFPicture) shape;
                        XSSFClientAnchor anchor = picture.getPreferredSize();
                        int rowIndex = anchor.getRow1();
                        int colIndex = anchor.getCol1();

                        if (colIndex == 2) {
                            Device device = rowDeviceMap.get(rowIndex);
                            if (device != null) {
                                try {
                                    byte[] imageData = picture.getPictureData().getData();

                                    // 检查图片大小，如果超过5MB则拒绝上传
                                    if (imageData.length > 5 * 1024 * 1024) {
                                        String errorMsg = "图片大小超过5MB限制，请压缩后重新上传";
                                        log.warn("行 {} 图片过大: {} bytes", rowIndex, imageData.length);
                                        // 将错误信息添加到该行的DTO中
                                        DeviceExcelImportDTO dto = rowDtoMap.get(rowIndex);
                                        if (dto != null) {
                                            dto.setErrorMessage(errorMsg);
                                            failedRecords.add(dto);
                                            failureCount++;
                                        }
                                        device.setDevicePic(null); // 设置为空，让插入继续
                                        continue; // 跳过当前图片处理
                                    }

                                    // 表示Excel表格中的第3列（因为索引从0开始计算）
                                    String extraValue = getCellValue(sheet, rowIndex, 2);
                                    String imageUrl = uploadAndGenerateUrl(imageData, extraValue);
                                    device.setDevicePic(imageUrl);

                                    // 2. 保存图片数据到DTO，用于错误报告
                                    rowImageMap.put(rowIndex, imageData);
                                } catch (Exception e) {
                                    log.error("行 {} 图片处理失败: {}", rowIndex, e.getMessage());
                                    device.setDevicePic(null); // 设置为空，让插入继续
                                }
                            }
                        }
                    }
                }
            } catch (Exception e) {
                log.error("图片处理失败：{}", e.getMessage(), e);
            }
        } catch (Exception e) {
            log.warn("图片处理过程中发生异常: {}", e.getMessage());
        }
    }


    private void processDataRowByRow1() {
        for (Integer rowIndex : rowIndexList) {
            Device device = rowDeviceMap.get(rowIndex);
            DeviceExcelImportDTO originalDto = rowDtoMap.get(rowIndex);
            try {
                // 设备类型
                DeviceType deviceType = params.getDeviceTypeService().queryByName(device.getTypeName());

                // 如果设备类型不存在，则创建新的设备类型
                if (deviceType == null) {
                    DeviceType newDeviceType = new DeviceType();
                    newDeviceType.setTypeName(device.getTypeName());
                    newDeviceType.setIsSupportBle("是".equals(originalDto.getIsSupportBle()) || "1".equals(originalDto.getIsSupportBle()));

                    // 设置定位方式
                    if (originalDto.getLocateMode() != null) {
                        switch (originalDto.getLocateMode()) {
                            case "无":
                                newDeviceType.setLocateMode("0");
                                break;
                            case "GPS":
                                newDeviceType.setLocateMode("1");
                                break;
                            case "基站":
                                newDeviceType.setLocateMode("2");
                                break;
                            case "wifi":
                                newDeviceType.setLocateMode("3");
                                break;
                            case "北斗":
                                newDeviceType.setLocateMode("4");
                                break;
                            default:
                                newDeviceType.setLocateMode(originalDto.getLocateMode());
                        }
                    }

                    // 设置通讯方式
                    if (originalDto.getCommunicationMode() != null) {
                        switch (originalDto.getCommunicationMode()) {
                            case "4G":
                                newDeviceType.setCommunicationMode("0");
                                break;
                            case "蓝牙":
                                newDeviceType.setCommunicationMode("1");
                                break;
                            case "4G&蓝牙":
                                newDeviceType.setCommunicationMode("2");
                                break;
                            default:
                                newDeviceType.setCommunicationMode(originalDto.getCommunicationMode());
                        }
                    }

                    newDeviceType.setAppModelDictionary(originalDto.getAppModelDictionary());
                    newDeviceType.setPcModelDictionary(originalDto.getPcModelDictionary());

                    DeviceTypeForm deviceTypeForm = new DeviceTypeForm();
                    BeanUtil.copyProperties(newDeviceType, deviceTypeForm, true);
                    // 创建新的设备类型
                    params.getDeviceTypeService().create(deviceTypeForm);

                    // 重新查询确保获取到正确的ID
                    deviceType = params.getDeviceTypeService().queryByName(device.getTypeName());
                }

                DeviceForm deviceForm = new DeviceForm();
                deviceForm.setDeviceName(device.getDeviceName());
                deviceForm.setDeviceType(deviceType.getId());
                deviceForm.setRemark(device.getRemark());
                deviceForm.setDeviceMac(device.getDeviceMac());
                deviceForm.setDeviceImei(device.getDeviceImei());
                deviceForm.setBluetoothName(device.getBluetoothName());
                deviceForm.setDevicePic(device.getDevicePic());
                params.getDeviceService().addDevice(deviceForm);
                successCount++;
                log.info("行 {} 数据插入成功", rowIndex);
            } catch (Exception e) {
                failureCount++;
                originalDto.setErrorMessage(e.getMessage());
                // originalDto.setErrorMessage("数据有误，请核对模板后，确认数据无误后，重新再试！！！");
                failedRecords.add(originalDto);
                log.error("行 {} 数据插入失败: {}", rowIndex, e.getMessage());
            }
        }
    }


    /**
     * 处理图片数据
     */
    private void processImages1() {
        try (OPCPackage opcPackage = OPCPackage.open(params.getFile().getInputStream())) {
            ZipSecureFile.setMinInflateRatio(-1.0d);
            XSSFWorkbook workbook = new XSSFWorkbook(opcPackage);
            XSSFSheet sheet = workbook.getSheetAt(0);

            XSSFDrawing drawing = sheet.getDrawingPatriarch();
            if (drawing == null) return;

            for (XSSFShape shape : drawing.getShapes()) {
                if (shape instanceof XSSFPicture) {
                    XSSFPicture picture = (XSSFPicture) shape;
                    XSSFClientAnchor anchor = picture.getPreferredSize();
                    int rowIndex = anchor.getRow1();
                    int colIndex = anchor.getCol1();

                    if (colIndex == 2) {
                        Device device = rowDeviceMap.get(rowIndex);
                        if (device != null) {
                            try {
                                byte[] imageData = picture.getPictureData().getData();

                                // 检查图片大小，如果超过5MB则拒绝上传
                                if (imageData.length > 5 * 1024 * 1024) {
                                    String errorMsg = "图片大小超过5MB限制，请压缩后重新上传";
                                    log.warn("行 {} 图片过大: {} bytes", rowIndex, imageData.length);
                                    // 将错误信息添加到该行的DTO中
                                    DeviceExcelImportDTO dto = rowDtoMap.get(rowIndex);
                                    if (dto != null) {
                                        dto.setErrorMessage(errorMsg);
                                        failedRecords.add(dto);
                                        failureCount++;
                                    }
                                    device.setDevicePic(null); // 设置为空，让插入继续
                                    continue; // 跳过当前图片处理
                                }

                                // 表示Excel表格中的第3列（因为索引从0开始计算）
                                String extraValue = getCellValue(sheet, rowIndex, 2);
                                String imageUrl = uploadAndGenerateUrl(imageData, extraValue);
                                device.setDevicePic(imageUrl);

                                // 2. 保存图片数据到DTO，用于错误报告
                                rowImageMap.put(rowIndex, imageData);
                            } catch (Exception e) {
                                log.error("行 {} 图片处理失败: {}", rowIndex, e.getMessage());
                                device.setDevicePic(null); // 设置为空，让插入继续
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.error("图片处理失败：{}", e.getMessage(), e);
        }
    }

    private String getCellValue(XSSFSheet sheet, int rowIndex, int colIndex) {
        XSSFRow row = sheet.getRow(rowIndex);
        if (row == null) return null;
        XSSFCell cell = row.getCell(colIndex);
        if (cell == null) return null;
        return cell.toString();
    }

    private String uploadAndGenerateUrl(byte[] imageData, String deviceMac) {
        if (imageData == null || imageData.length == 0) {
            log.warn("图片数据为空");
            return null;
        }
        try {
            // 如果图片超过500KB，则进行压缩优化
            if (imageData.length > 500 * 1024) {
                log.info("检测到大图片 ({} bytes)，正在进行压缩优化...", imageData.length);
                imageData = ImageCompressUtil.compressImage(imageData, 500 * 1024); // 压缩到500KB以下
            }

            String fileExtension = "jpg";
            String newFileName = "PS_" + new Random(8) + "." + fileExtension;
            SysOssVo upload = params.getOssService().upload(imageData, newFileName);
            log.info("图片保存成功，URL: {}", upload.getUrl());
            return upload.getUrl();
        } catch (Exception e) {
            log.error("保存图片失败", e);
            return null;
        }
    }

}

