package jnpf.cultivate.v2.controller.web.identify;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;
import jnpf.base.ActionResult;
import jnpf.base.vo.PageListVO;
import jnpf.cultivate.v2.service.FtbCultivateIdentifyCategoriesService;
import jnpf.cultivate.v2.service.FtbCultivateIdentifyItemsPoolService;
import jnpf.cultivate.v2.util.CultivateIdentityUtil;
import jnpf.model.cultivate.CultivatePage;
import jnpf.model.cultivate.po.FtbCultivateIdentifyCategories;
import jnpf.model.cultivate.po.FtbCultivateIdentifyItemsPool;
import jnpf.model.cultivate.v2.common.req.V2BatchByPrimaryIdReq;
import jnpf.model.cultivate.v2.common.vo.V2PreImportVo;
import jnpf.model.cultivate.v2.item_pool.req.IdentifyItemsPoolReq;
import jnpf.model.cultivate.v2.item_pool.req.SaveCultivateIdentifyItemsPoolReq;
import jnpf.model.cultivate.v2.item_pool.vo.FtbCultivateIdentifyItemsPoolVo;
import jnpf.model.cultivate.v2.item_pool.vo.V2IdentifyItemExceptionVo;
import jnpf.model.cultivate.v2.item_pool.vo.V2IdentifyItemVo;
import jnpf.util.RedisUtil;
import jnpf.util.excelv2.util.ExcelUtils;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.*;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;

/**
 * web实操鉴定项模块
 *
 * @author lingma
 * @since 2026-02-24
 */
@Slf4j
@RestController
@RequestMapping("/v2/web/identify/items-pool")
@AllArgsConstructor
public class V2CultivateIdentifyItemsPoolController {
    final private FtbCultivateIdentifyItemsPoolService itemsPoolService;
    final private FtbCultivateIdentifyCategoriesService categoriesService;
    final private RedisUtil redisUtil;


    /**
     * 查询鉴定项列表
     *
     * @return 鉴定项池列表
     */
    @GetMapping("/list")
    public ActionResult<List<FtbCultivateIdentifyItemsPool>> list() {
        return ActionResult.success("查询成功", itemsPoolService.listAll());
    }


    /**
     * 鉴定项列表(分页)
     *
     * @param req 查询参数
     * @return {@link ActionResult}<{@link PageListVO}<{@link FtbCultivateIdentifyItemsPoolVo}>>
     */
    @GetMapping("/page-list")
    public ActionResult<PageListVO<FtbCultivateIdentifyItemsPoolVo>> pageList(IdentifyItemsPoolReq req) {
        return ActionResult.success(CultivatePage.coverPageList(itemsPoolService.webPageList(req)));
    }

    /**
     * 根据ID获取鉴定项详情
     *
     * @param id 鉴定项池ID
     * @return 鉴定项池详情
     */
    @GetMapping("/{id}")
    public ActionResult<FtbCultivateIdentifyItemsPoolVo> getInfo(@PathVariable("id") String id) {
        return ActionResult.success("查询成功", itemsPoolService.getInfo(id));
    }

    /**
     * 添加鉴定项
     *
     * @param req 鉴定项池信息
     * @return 添加结果
     */
    @PostMapping("/add")
    public ActionResult<Boolean> add(@Valid @RequestBody SaveCultivateIdentifyItemsPoolReq req) {
        req.preCheck();
        itemsPoolService.addData(req);
        return ActionResult.success("添加成功", true);
    }


    /**
     * 修改鉴定项
     *
     * @param id  鉴定项池ID
     * @param req 鉴定项池信息
     * @return 修改结果
     */
    @PutMapping("/update/{id}")
    public ActionResult<Boolean> update(@PathVariable("id") String id, @Valid @RequestBody SaveCultivateIdentifyItemsPoolReq req) {
        req.preCheck();
        itemsPoolService.updateData(id, req);
        return ActionResult.success("编辑成功", true);
    }

    /**
     * 删除鉴定项
     *
     * @param id 鉴定项池ID
     * @return 删除结果
     */
    @DeleteMapping("/del/{id}")
    public ActionResult<Boolean> del(@PathVariable("id") String id) {
        itemsPoolService.deleteData(id);
        return ActionResult.success("删除成功", true);
    }

    /**
     * 批量删除鉴定项
     *
     * @param req 批量删除参数
     * @return 删除结果
     */
    @DeleteMapping("/batch-del")
    public ActionResult<Boolean> batchDel(@RequestBody @Validated V2BatchByPrimaryIdReq req) {
        itemsPoolService.batchDel(req);
        return ActionResult.success("删除成功", true);
    }


    /**
     * 下载导入模版
     *
     * @param response
     * @throws IOException
     */
    @GetMapping("/down-template")
    public void importTemplate(HttpServletResponse response) throws IOException {
        ExcelUtils<V2IdentifyItemVo> util = new ExcelUtils<>(V2IdentifyItemVo.class);

        List<String> allNameList = categoriesService.getAllNameList();
        if (CollUtil.isNotEmpty(allNameList)) {
            List<V2IdentifyItemVo> example = new ArrayList<>();
            V2IdentifyItemVo item = new V2IdentifyItemVo();
            item.setCateName(allNameList.get(0));
            item.setScore("0~100");
            item.setItemName("鉴定项内容");
            example.add(item);
            util.exportExcel(response, "鉴定项导入模版.xlsx", "鉴定项导入模版", example);
        } else {
            util.exportExcel(response, "鉴定项导入模版.xlsx", "鉴定项导入模版", null);
        }

    }

    /**
     * 鉴定项导入
     *
     * @param file
     * @return
     */
    @PostMapping("/import")
    public ActionResult<V2PreImportVo> preImportData(@RequestPart("file") MultipartFile file) throws IOException {
        // 将文件读取为字节数组，避免InputStream只能读取一次的问题
        byte[] fileBytes = file.getBytes();

        //读取excel的第一行数据 判断表头   鉴定项内容 、鉴定项分类 、分值
        validateExcelHeader(new java.io.ByteArrayInputStream(fileBytes));

        ExcelUtils<V2IdentifyItemVo> util = new ExcelUtils<>(V2IdentifyItemVo.class);
        List<V2IdentifyItemVo> list = util.importExcel(new java.io.ByteArrayInputStream(fileBytes));
        if (CollUtil.isNotEmpty(list) && list.size() > 200) {
            throw new RuntimeException("导入失败，请勿导入大于200条数据");
        }
        V2PreImportVo v2PreImportVo = new V2PreImportVo();
        try {
            v2PreImportVo = checkImportItem(list);
        } catch (Exception e) {

        }
        if (CollUtil.isEmpty(v2PreImportVo.getNormal()) && CollUtil.isEmpty(v2PreImportVo.getError())) {
            throw new RuntimeException("导入失败，未检测到数据");
        }
        if (CollUtil.isEmpty(v2PreImportVo.getError())) {
            try {
                itemsPoolService.batchAddData(v2PreImportVo.getNormal());
                return ActionResult.success("导入成功", v2PreImportVo);
            } catch (Exception e) {
                throw new RuntimeException("导入失败");
            }
        }
        redisUtil.insert(v2PreImportVo.getUniqueId(), v2PreImportVo, 60 * 60);
        return ActionResult.success("成功", v2PreImportVo);
    }

    /**
     * 验证Excel表头是否正确
     *
     * @param inputStream Excel文件输入流
     */
    private void validateExcelHeader(InputStream inputStream) {
        try {
            // 使用POI读取Excel文件（不关闭Workbook，避免关闭底层的InputStream）
            Workbook workbook = WorkbookFactory.create(inputStream);
            Sheet sheet = workbook.getSheetAt(0);

            if (sheet == null) {
                throw new RuntimeException("导入模版不正确！");
            }

            // 获取第一行（表头行）
            Row headerRow = sheet.getRow(0);
            if (headerRow == null || headerRow.getPhysicalNumberOfCells() == 0) {
                throw new RuntimeException("导入模版不正确！");
            }

            // 定义期望的表头（按照V2IdentifyItemVo中@Excel注解的顺序）
            List<String> expectedHeaders = Arrays.asList("鉴定项内容", "鉴定项分类", "分值");

            // 提取实际表头值
            List<String> actualHeaders = new ArrayList<>();
            for (int i = 0; i < headerRow.getPhysicalNumberOfCells(); i++) {
                Cell cell = headerRow.getCell(i);
                if (cell != null) {
                    String cellValue = getCellValue(cell);
                    if (StringUtils.isNotEmpty(cellValue)) {
                        actualHeaders.add(cellValue.trim());
                    }
                }
            }

            // 将表头列表转换为字符串进行比较
            String expectedHeaderStr = String.join(",", expectedHeaders);
            String actualHeaderStr = String.join(",", actualHeaders);

            // 验证表头是否正确
            if (!expectedHeaderStr.equals(actualHeaderStr)) {
                throw new RuntimeException("导入模版不正确！");
            }

        } catch (RuntimeException e) {
            throw e;
        } catch (Exception e) {
            log.error("验证Excel表头失败", e);
            throw new RuntimeException("导入失败，Excel文件格式错误");
        }
        // 注意：不关闭Workbook，避免关闭底层的InputStream
        // ByteArrayInputStream由调用方管理生命周期
    }

    /**
     * 获取单元格的字符串值
     *
     * @param cell 单元格
     * @return 单元格的字符串值
     */
    private String getCellValue(Cell cell) {
        if (cell == null) {
            return "";
        }
        switch (cell.getCellType()) {
            case STRING:
                return cell.getStringCellValue();
            case NUMERIC:
                if (DateUtil.isCellDateFormatted(cell)) {
                    return cell.getDateCellValue().toString();
                } else {
                    // 避免数字后面带.0
                    double numericValue = cell.getNumericCellValue();
                    if (numericValue == Math.floor(numericValue)) {
                        return String.valueOf((long) numericValue);
                    } else {
                        return String.valueOf(numericValue);
                    }
                }
            case BOOLEAN:
                return String.valueOf(cell.getBooleanCellValue());
            case FORMULA:
                return cell.getCellFormula();
            default:
                return "";
        }
    }

    private V2PreImportVo checkImportItem(List<V2IdentifyItemVo> list) {
        List<FtbCultivateIdentifyCategories> allCateList = categoriesService.getAllList();
        List<FtbCultivateIdentifyItemsPool> dataList = itemsPoolService.listAll();
        List<String> existNameList = new ArrayList<>();
        for (FtbCultivateIdentifyItemsPool itemsPool : dataList) {
            String s = CultivateIdentityUtil.buildRepeatKey(itemsPool);
            existNameList.add(s);
        }
        List<String> cateNameList = new ArrayList<>();
        Map<String, String> cateNameMap = new HashMap<>();
        for (FtbCultivateIdentifyCategories ftbCultivateIdentifyCategories : allCateList) {
            cateNameMap.put(ftbCultivateIdentifyCategories.getName(), ftbCultivateIdentifyCategories.getId());
            cateNameList.add(ftbCultivateIdentifyCategories.getName());
        }
        Set<String> nameSet = new HashSet<>();
        for (V2IdentifyItemVo v2IdentifyItemVo : list) {
            if (StringUtils.isEmpty(v2IdentifyItemVo.getItemName())) {
                v2IdentifyItemVo.setMsg("鉴定项内容不能为空");
                v2IdentifyItemVo.setSuccess(1);
                continue;
            }
            //判断鉴定项内容不能超过500个字
            if (v2IdentifyItemVo.getItemName().length() > 500) {
                v2IdentifyItemVo.setMsg("鉴定项内容不能超过500个字");
                v2IdentifyItemVo.setSuccess(1);
                continue;
            }

            if (StringUtils.isEmpty(v2IdentifyItemVo.getCateName())) {
                v2IdentifyItemVo.setMsg("鉴定项分类不能为空");
                v2IdentifyItemVo.setSuccess(1);
                continue;
            }
            if (StringUtils.isEmpty(v2IdentifyItemVo.getScore())) {
                v2IdentifyItemVo.setMsg("分值不能为空");
            }
            CultivateIdentityUtil.parseAndValidateScore(v2IdentifyItemVo);
            if (v2IdentifyItemVo.getSuccess().equals(1)) {
                continue;
            }
            if (!cateNameList.contains(v2IdentifyItemVo.getCateName())) {
                v2IdentifyItemVo.setMsg("鉴定项分类不存在");
                v2IdentifyItemVo.setSuccess(1);
            }
            v2IdentifyItemVo.setCateId(cateNameMap.get(v2IdentifyItemVo.getCateName()));
            String repeat = CultivateIdentityUtil.buildRepeatKey(v2IdentifyItemVo);
            if (nameSet.contains(repeat)) {
                v2IdentifyItemVo.setMsg("鉴定项重复");
            }
            if (existNameList.contains(repeat)) {
                v2IdentifyItemVo.setMsg("鉴定项已存在");
                v2IdentifyItemVo.setSuccess(1);
            }
            nameSet.add(repeat);
        }
        V2PreImportVo v2PreImportVo = new V2PreImportVo();
        v2PreImportVo.setNormal(list.stream().filter(v2IdentifyItemVo -> v2IdentifyItemVo.getSuccess().equals(0)).collect(Collectors.toList()));
        v2PreImportVo.setError(list.stream().filter(v2IdentifyItemVo -> v2IdentifyItemVo.getSuccess().equals(1)).collect(Collectors.toList()));
        v2PreImportVo.setUniqueId(UUID.randomUUID().toString());
        v2PreImportVo.setNormalNumber(v2PreImportVo.getNormal().size());
        v2PreImportVo.setErrorNumber(v2PreImportVo.getError().size());
        return v2PreImportVo;

    }

    /**
     * 鉴定项异常数据导出
     *
     * @param key 预检测导入时返回的唯一标识(必传)，用于导出异常数据
     */
    @GetMapping("/exception/{key}")
    public void exceptionDataExport(@PathVariable(name = "key") String key, HttpServletResponse response) throws IOException {


        if (!redisUtil.exists(key)) {
            throw new RuntimeException("导入数据已过期，请重新导入!");
        }
        V2PreImportVo data = JSON.parseObject(redisUtil.getString(key).toString(), V2PreImportVo.class);
        if (data == null || CollUtil.isEmpty(data.getError())) {
            throw new RuntimeException("无异常数据可以导出");
        }
        ExcelUtils<V2IdentifyItemExceptionVo> util = new ExcelUtils<>(V2IdentifyItemExceptionVo.class);
        List<V2IdentifyItemExceptionVo> v2IdentifyItemExceptionVos = BeanUtil.copyToList(data.getError(), V2IdentifyItemExceptionVo.class);
        util.exportExcel(response, "鉴定项导入异常数据.xlsx", "鉴定项导入异常数据", v2IdentifyItemExceptionVos);

    }
}