package com.bonus.material.device.controller;

import cn.hutool.core.convert.Convert;
import com.bonus.common.biz.config.ListPagingUtil;
import com.bonus.common.biz.domain.BmCompanyInfo;
import com.bonus.common.core.annotation.Excel;
import com.bonus.common.core.utils.poi.ExcelUtil;
import com.bonus.common.core.web.controller.BaseController;
import com.bonus.common.core.web.domain.AjaxResult;
import com.bonus.common.core.web.page.TableDataInfo;
import com.bonus.common.log.annotation.SysLog;
import com.bonus.common.log.enums.OperaType;
import com.bonus.common.security.utils.SecurityUtils;
import com.bonus.material.devConfig.domain.EquipmentProperty;
import com.bonus.material.devchange.domain.MaDevInfo;
import com.bonus.material.devchange.domain.MaDevInfoXlsx;
import com.bonus.material.device.domain.DevInfo;
import com.bonus.material.device.domain.EquipmentImportDTO;
import com.bonus.material.device.domain.dto.InfoMotionDto;
import com.bonus.material.device.domain.vo.DevInfoVo;
import com.bonus.material.device.domain.vo.DevMergeVo;
import com.bonus.material.device.service.DevInfoService;
import com.bonus.material.device.service.DevMergeService;
import com.bonus.material.utils.CenterExcelUtil;
import com.bonus.material.utils.FolderZipUtil;
import com.bonus.material.utils.MultiSheetExcelUtil;
import com.bonus.material.utils.ReflectUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.poi.ss.usermodel.Sheet;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;


/**
 * 设备信息Controller
 *
 * @author syruan
 */
@Slf4j
@RestController
@RequestMapping("/order")
@Api(value = "设备信息", tags = "设备管理")
public class DevMergeController extends BaseController {

    @Resource
    private DevMergeService service;


    @Resource
    private DevInfoService devInfoService;

    /**
     * 查询设备信息列表(首页装备共享大厅查询列表专用)
     */
    @ApiOperation(value = "装备新增台账-列表")
    @GetMapping("/orderList")
    public AjaxResult orderList(DevMergeVo devInfo) {
        List<DevMergeVo> list = service.list(devInfo);
        Integer pageIndex = Convert.toInt(devInfo.getPageNum(), 1);
        Integer pageSize = Convert.toInt(devInfo.getPageSize(), 10);
        return AjaxResult.success(ListPagingUtil.paging(pageIndex, pageSize, list));
    }

    /**
     * 获取台账中设备信息详细信息
     */
    @ApiOperation(value = "装备台账-新增单个台账")
    @PostMapping("/addOrder")
    public AjaxResult addOrder() {
        try {
            return service.addOrder();
        } catch (Exception e) {
            logger.error("报错啦", e);
            return AjaxResult.error("调用异常，请联系管理员");
        }
    }

    /**
     * 提交设备台账
     */
    @ApiOperation(value = "装备台账-提交设备台账")
    @PostMapping("/submitOrder")
    public AjaxResult submitOrder(@RequestBody DevMergeVo o) {
        try {
            return service.submitOrder(o);
        } catch (Exception e) {
            logger.error("报错啦", e);
            return AjaxResult.error("调用异常，请联系管理员");
        }
    }


    /**
     * 提交设备台账
     */
    @ApiOperation(value = "装备台账-删除")
    @PostMapping("/delOrder")
    public AjaxResult delOrder(@RequestBody DevMergeVo o) {
        try {
            return service.delOrder(o);
        } catch (Exception e) {
            logger.error("报错啦", e);
            return AjaxResult.error("调用异常，请联系管理员");
        }
    }


    /**
     * cha
     *
     * @param o
     * @return
     */
    @ApiOperation(value = "设备台账")
    @GetMapping("/getDevice")
    public AjaxResult getDevice(MaDevInfo o) {
        try {
            startPage();
            List<MaDevInfo> list = service.getDevice(o);
            return AjaxResult.success(getDataTable(list));
        } catch (Exception e) {
            logger.error("报错啦", e);
            return AjaxResult.error("调用异常，请联系管理员");
        }
    }

    @ApiOperation(value = "设备台账")
    @GetMapping("/getDeviceByOrderId")
    public AjaxResult getDeviceByOrderId(MaDevInfo o) {
        try {
            startPage();
            List<MaDevInfo> list = service.getDeviceByOrderId(o);
            return AjaxResult.success(getDataTable(list));
        } catch (Exception e) {
            logger.error("报错啦", e);
            return AjaxResult.error("调用异常，请联系管理员");
        }
    }


    /**
     * 获取台账中设备信息详细信息
     */
    @ApiOperation(value = "装备台账-新增单个设备草稿")
    @PostMapping("/interDevice")
    public AjaxResult interDevice(@RequestBody MaDevInfo maDevInfo) {
        return service.interDevice(maDevInfo);
    }

    /**
     * 获取台账中设备信息详细信息
     */
    @ApiOperation(value = "装备台账-新增单个设备草稿")
    @PostMapping("/updateDevice")
    public AjaxResult updateDevice(@RequestBody MaDevInfo maDevInfo) {
        return service.updateDevice(maDevInfo);
    }

    /**
     * 获取台账中设备信息详细信息
     */
    @ApiOperation(value = "装备台账-编辑增单个设备草稿")
    @PostMapping("/editDevice")
    public AjaxResult editDevice(@RequestBody @Valid DevInfo devInfo) {
        try {
            return devInfoService.updateDevInfo(devInfo);
        } catch (Exception e) {
            logger.error("报错啦", e);
            return AjaxResult.error("调用异常，请联系管理员");
        }
    }


    /**
     * 获取台账中设备信息详细信息
     */
    @ApiOperation(value = "装备台账-单个台账设备列表")
    @GetMapping("/devList")
    public AjaxResult devList(DevInfoVo devInfo) {
        List<DevInfoVo> list = service.devList(devInfo);
        Integer pageIndex = Convert.toInt(devInfo.getPageNum(), 1);
        Integer pageSize = Convert.toInt(devInfo.getPageSize(), 10);
        return AjaxResult.success(ListPagingUtil.paging(pageIndex, pageSize, list));
    }


    @ApiOperation(value = "装备台账-删除增单个设备草稿")
    @PostMapping("/delDevice")
    public AjaxResult delDevice(@RequestBody Long[] maIds) {
        try {
            return toAjax(devInfoService.deleteDevInfoByMaIds(maIds));
        } catch (Exception e) {
            logger.error("报错啦", e);
            return AjaxResult.error("调用异常，请联系管理员");
        }
    }


    /**
     * 提交设备台账
     */
    @ApiOperation(value = "装备审核")
    @PostMapping("/checkDevice")
    public AjaxResult checkDevice(@RequestBody DevMergeVo o) {
        try {
            return service.checkDevice(o);
        } catch (Exception e) {
            logger.error("报错啦", e);
            return AjaxResult.error("调用异常，请联系管理员");
        }
    }


    /**
     * 获取台账中设备信息详细信息
     */
    @ApiOperation(value = "装备台账-新增单个设备草稿")
    @PostMapping("/addDevice")
    public AjaxResult addDevice(@RequestBody @Valid DevInfo devInfo) {
        try {
            devInfo.setEntryStatus("3");
            AjaxResult ajaxResult = devInfoService.insertDevInfo(devInfo);
            if (ajaxResult.isSuccess()) {
                service.insertOrderDevReal(devInfo.getOrderId(), devInfo.getMaId());
            }
            return ajaxResult;
        } catch (Exception e) {
            logger.error("报错啦", e);
            return AjaxResult.error("调用异常，请联系管理员");
        }
    }


    /**
     * 查询所有一级类型（顶级类型）
     *
     * @return 一级类型列表
     */
    @GetMapping("/firstLevel")
    public AjaxResult getFirstLevelTypes() {
        return service.findFirstLevelTypes();
    }

    /**
     * 根据一级类型ID查询其下的二、三级类型
     *
     * @param firstLevelId 一级类型ID
     * @return 二、三级类型列表
     */
    @GetMapping("/secondAndThirdLevel")
    public AjaxResult getSecondAndThirdLevelTypes(@RequestParam Long firstLevelId) {
        return service.findSecondAndThirdLevelTypes(firstLevelId);
    }

    /**
     * 根据三级类型ID查询其下的四、五、六级类型
     *
     * @param thirdLevelId 三级类型ID
     * @return 四、五、六级类型列表
     */
    @GetMapping("/fourthToSixthLevel")
    public AjaxResult getFourthToSixthLevelTypes(@RequestParam Long thirdLevelId) {
        return service.getFourthToSixthLevelTypes(thirdLevelId);
    }

    @GetMapping("/getSecondToFifthLevelTypes")
    public AjaxResult getSecondToFifthLevelTypes(@RequestParam Long firstLevelId) {
        return service.getSecondToFifthLevelTypes(firstLevelId);
    }


    @PostMapping("/importData")
    @SysLog(title = "导入装备", businessType = OperaType.IMPORT, logType = 0, module = "装备管理->批量导入", details = "导入装备信息")
    public AjaxResult importData(MultipartFile file, String orderId) {
        try {
            // 先计算Excel中的公式，将公式结果转换为文本值
            MultipartFile processedFile = processExcelFormulas(file);

            ExcelUtil<EquipmentImportDTO> util = new ExcelUtil<>(EquipmentImportDTO.class);
            List<EquipmentImportDTO> list = util.importExcel(processedFile.getInputStream(), 0);
            return service.importData(list, orderId);
        } catch (Exception e) {
            logger.error(e.toString(), e);
            return error(e.getMessage());
        }

    }

    /**
     * 处理Excel中的公式，将公式计算结果转换为文本值
     * 这样ExcelUtil就能正确读取公式单元格的值
     */
    private MultipartFile processExcelFormulas(MultipartFile file) throws Exception {
        try (InputStream inputStream = file.getInputStream();
             Workbook workbook = new XSSFWorkbook(inputStream)) {

            // 创建公式计算器
            FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();

            // 获取第一个Sheet（装备信息）
            Sheet sheet = workbook.getSheetAt(0);

            // 遍历所有行
            for (Row row : sheet) {
                if (row == null) continue;

                // 遍历所有单元格
                for (Cell cell : row) {
                    if (cell == null) continue;

                    // 如果是公式单元格，计算公式并将结果转换为文本值
                    if (cell.getCellType() == CellType.FORMULA) {
                        try {
                            // 计算公式
                            CellValue cellValue = evaluator.evaluate(cell);

                            // 根据计算结果类型，将公式转换为对应的值
                            switch (cellValue.getCellType()) {
                                case STRING:
                                    String stringValue = cellValue.getStringValue();
                                    cell.setCellFormula(null); // 移除公式
                                    cell.setCellValue(stringValue); // 设置为文本值
                                    break;
                                case NUMERIC:
                                    double numericValue = cellValue.getNumberValue();
                                    cell.setCellFormula(null);
                                    cell.setCellValue(numericValue);
                                    break;
                                case BOOLEAN:
                                    boolean booleanValue = cellValue.getBooleanValue();
                                    cell.setCellFormula(null);
                                    cell.setCellValue(booleanValue);
                                    break;
                                case BLANK:
                                case ERROR:
                                default:
                                    // 空值或错误，转换为空字符串
                                    cell.setCellFormula(null);
                                    cell.setCellValue("");
                                    break;
                            }
                        } catch (Exception e) {
                            // 公式计算失败，设置为空字符串
                            logger.warn("公式计算失败，单元格位置：行{} 列{}，错误：{}",
                                       row.getRowNum(), cell.getColumnIndex(), e.getMessage());
                            cell.setCellFormula(null);
                            cell.setCellValue("");
                        }
                    }
                }
            }

            // 将处理后的Workbook写入到字节数组
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            workbook.write(baos);
            byte[] bytes = baos.toByteArray();

            // 创建新的MultipartFile对象
            return new org.springframework.mock.web.MockMultipartFile(
                file.getName(),
                file.getOriginalFilename(),
                file.getContentType(),
                bytes
            );
        }
    }


    /**
     * 下载指定空文件夹结构的 ZIP 包
     * 目标结构：
     * ├── business/
     * │   ├── report/
     * │   └── data/
     * └── temp/
     * 访问路径：http://localhost:8080/download/zip
     */
    @PostMapping("/zip")
    public void downloadEmptyFolderZip(HttpServletResponse response, String orderId) {
        service.downloadEmptyFolderZip(response, orderId);
    }

    /**
     * 上传包含多个一级目录的ZIP包
     * 无需传设备ID，自动识别ZIP内的Apply-xxx目录
     */
    @PostMapping("/upload-multi")
    public AjaxResult uploadMultiDeviceZip(@RequestParam MultipartFile file, String orderId) {
        return service.uploadAndUnzipMultiDeviceZip(file, orderId);
    }

    /**
     * 下载导入模板（带特征项联动功能）
     */
    @PostMapping("/template")
    public void downloadTemplate(HttpServletResponse response) {
        try {
            // 1. 查询所有装备类型及其特征项
            Map<String, List<EquipmentProperty>> typePropertiesMap = service.getAllTypePropertiesMap();

            // 2. 查询装备类型列表（用于下拉框）
            List<String> professionList = service.listAllProfessionNames();
            String[] professionArray = professionList.toArray(new String[0]);

            // 3. 查询生产厂家列表（用于下拉框）
            List<String> manufacturerList = service.listAllManufacturerNames();
            String[] manufacturerArray = manufacturerList.toArray(new String[0]);

            // 4. 计数单位列表（用于下拉框）
            String[] unitArray = new String[]{"台", "套", "个", "辆", "件"};

            // 5. 使用多Sheet工具类生成模板
            MultiSheetExcelUtil.generateMultiSheetTemplate(
                    response,
                    "装备信息导入模板",
                    typePropertiesMap,
                    professionArray,
                    manufacturerArray,
                    unitArray
            );
        } catch (Exception e) {
            log.error("生成模板失败", e);
            throw new RuntimeException("生成模板失败: " + e.getMessage(), e);
        }
    }
}
