package jnpf.cultivate.v2.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jnpf.cultivate.mapper.CultivateCoverInfoMapper;
import jnpf.cultivate.mapper.CultivateIdentifyTableMapper;
import jnpf.cultivate.service.CultivateIdentifyItemsService;
import jnpf.cultivate.utils.UserApiV2Util;
import jnpf.cultivate.v2.service.FtbCultivateIdentifyItemsPoolService;
import jnpf.cultivate.v2.service.FtbCultivateLabelService;
import jnpf.cultivate.v2.service.V2CultivateIdentifyTableService;
import jnpf.cultivate.v2.util.CultivateIdentityUtil;
import jnpf.entity.cultivate.CultivateIdentifyItems;
import jnpf.entity.cultivate.CultivateIdentifyTable;
import jnpf.enums.AppraisalScoreTypeEnum;
import jnpf.enums.cultivate.IdentifyItemExceptionEnum;
import jnpf.enums.cultivate.IdentifyScoreTypeEnum;
import jnpf.model.cultivate.dto.learn.BatchCommonCountDto;
import jnpf.model.cultivate.po.FtbCultivateIdentifyItemsPool;
import jnpf.model.cultivate.po.common.FtbCultivateCoverInfoEntity;
import jnpf.model.cultivate.v2.identify.req.*;
import jnpf.model.cultivate.v2.identify.vo.V2CateIdentifyTableVo;
import jnpf.model.cultivate.v2.identify.vo.V2IdentifyTableInfoVo;
import jnpf.model.cultivate.v2.identify.vo.V2IdentifyTableListVo;
import jnpf.model.cultivate.v2.identify.vo.V2IdentifyTableScoreConfigVo;
import jnpf.model.cultivate.v2.label.vo.FtbCultivateLabelVo;
import jnpf.model.enums.SelfrowingEnum;
import jnpf.util.SelfGrowthUtil;
import jnpf.util.UserProvider;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;


@Slf4j
@Service
public class V2CultivateIdentifyTableServiceImpl implements V2CultivateIdentifyTableService {

    @Autowired
    private CultivateIdentifyTableMapper cultivateIdentifyTableMapper;

    @Autowired
    private CultivateIdentifyItemsService itemsService;

    @Autowired
    private FtbCultivateIdentifyItemsPoolService ftbCultivateIdentifyItemsPoolService;

    @Autowired
    private CultivateCoverInfoMapper cultivateCoverInfoMapper;


    @Autowired
    private FtbCultivateLabelService ftbCultivateLabelService;


    /**
     * 鉴定表/列表
     *
     * @param req 帅选条件
     * @return Page<V2IdentifyTableListVo>
     */
    @Override
    public Page<V2IdentifyTableListVo> getPageList(V2IdentifyTableListReq req) {

        Page<V2IdentifyTableListVo> page = this.cultivateIdentifyTableMapper.getPageListV2(Page.of(req.getCurrentPage(), req.getPageSize()), req);
        if (CollUtil.isNotEmpty(page.getRecords())) {
            List<String> tableIdList = page.getRecords().stream().map(V2IdentifyTableListVo::getId).collect(Collectors.toList());
            List<BatchCommonCountDto> countDtoList = itemsService.countForTableId(tableIdList);
            Map<String, Integer> countMap = new HashMap<>();
            if (CollUtil.isNotEmpty(countDtoList)) {
                countMap = countDtoList.stream().collect(Collectors.toMap(BatchCommonCountDto::getSelectKey, BatchCommonCountDto::getNum));
            }
            for (V2IdentifyTableListVo record : page.getRecords()) {
                Integer cnt = countMap.get(record.getId());
                record.setIdentifyCount(cnt == null ? 0 : cnt);
            }
        }
        return page;
    }

    /**
     * 鉴定表/详情
     *
     * @param tableId 帅选条件
     * @return V2IdentifyTableInfoVo
     */
    @Override
    public V2IdentifyTableInfoVo getInfo(String tableId) {
        CultivateIdentifyTable table = this.cultivateIdentifyTableMapper.selectById(tableId);
        if (table == null || table.getDeleteMark() == 1) {
            throw new RuntimeException("鉴定表不存在或者已经被删除");
        }
        V2IdentifyTableInfoVo tableInfoVo = new V2IdentifyTableInfoVo();
        tableInfoVo.setId(table.getId());
        tableInfoVo.setName(table.getName());
        tableInfoVo.setRuleDesc(table.getRuleDesc());
        tableInfoVo.setPassType(table.getPassType());
        tableInfoVo.setPassScore(table.getPassScore());
        tableInfoVo.setExcellentType(table.getExcellentType());
        tableInfoVo.setExcellentScore(table.getExcellentScore());
        tableInfoVo.setLabelId(table.getLabelId());
        tableInfoVo.setCoverId(table.getCoverId());
        tableInfoVo.setCoverUrl(table.getCoverUrl());
        tableInfoVo.setScoreType(table.getScoreType());
        tableInfoVo.setCertificateId(table.getCertificateId());
        if (StringUtils.isNotEmpty(table.getScoreConfig())) {
            tableInfoVo.setScoreConfig(JSON.parseArray(table.getScoreConfig(), V2IdentifyTableScoreConfigVo.class));
        }


        tableInfoVo.setIdentifyItemList(itemsService.listWithCategory(tableId));


        return tableInfoVo;
    }

    /**
     * 鉴定表/新增
     *
     * @param req 帅选条件
     */

    @Override
    @Transactional
    public void saveData(V2IdentifyTableSaveReq req) {
        preCheck(req);
        String userId = UserProvider.getUser().getUserId();
        // 检查课程名称是否重复
        LambdaQueryWrapper<CultivateIdentifyTable> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(CultivateIdentifyTable::getName, req.getName());
        queryWrapper.eq(CultivateIdentifyTable::getDeleteMark, 0); // 只检查有效的课程
        long count = cultivateIdentifyTableMapper.selectCount(queryWrapper);
        if (count > 0) {
            throw new RuntimeException("鉴定表名称已经存在");
        }
        CultivateIdentifyTable tableSave = CultivateIdentifyTable.builder()
                .name(req.getName())
                .ruleId(SelfGrowthUtil.provideACustomIDBasedOnTheModule(SelfrowingEnum.IDENTIFY))
                .ruleDesc(req.getRuleDesc())
                .passType(req.getPassType())
                .passScore(req.getPassScore())
                .excellentType(req.getExcellentType())
                .excellentScore(req.getExcellentScore())
                .coverId(req.getCoverId())
                .coverUrl(req.getCoverUrl())
                .labelId(req.getLabelId())
                .scoreType(req.getScoreType())
                .certificateId(req.getCertificateId())
                .scoreConfig(CollUtil.isNotEmpty(req.getScoreConfig()) ? JSON.toJSONString(req.getScoreConfig()) : "")
                .build();
        tableSave.setCreatorTime(new Date());
        tableSave.setLastModifyTime(new Date());
        tableSave.setCreatorUserId(userId);
        tableSave.setLastModifyUserId(userId);
        tableSave.setTenantId(UserProvider.getUser().getTenantId());
        tableSave.setDeleteMark(0);
        cultivateIdentifyTableMapper.insert(tableSave);
        //批量新增鉴定项

        addIdentifyItemsData(req, tableSave.getId());
    }

    private void addIdentifyItemsData(V2IdentifyTableSaveReq req, String tableId) {
        List<CultivateIdentifyItems> batchSaveItemsList = new ArrayList<>();
        for (V2IdentifyItemsSaveReq items : req.getIdentifyItemList()) {
            CultivateIdentifyItems.CultivateIdentifyItemsBuilder cultivateIdentifyItemsBuilder = CultivateIdentifyItems.builder()
                    .tableId(tableId)
                    .cateId(items.getCateId())
                    .name(items.getName())
                    .score(items.getScore())
                    .type(items.getType())
                    .minScore(items.getMinScore())
                    .maxScore(items.getMaxScore())
                    .poolId(items.getPoolId())
                    .businessId(items.getBusinessId())
                    .isAbnormal(IdentifyItemExceptionEnum.NORMAL.getCode());
            batchSaveItemsList.add(cultivateIdentifyItemsBuilder.build());
        }
        if (CollUtil.isNotEmpty(batchSaveItemsList)) {
            this.itemsService.saveBatch(batchSaveItemsList);
        }
    }

    private void preCheck(V2IdentifyTableSaveReq req) {
        if (req.getScoreType().equals(IdentifyScoreTypeEnum.LEVEL_SYSTEM.getCode())) {

            if (CollUtil.isEmpty(req.getScoreConfig())) {
                throw new RuntimeException("请选择等级制配置");
            }
            if (req.getScoreConfig().size() < 2) {
                throw new RuntimeException("等级制配置至少需要两个");
            }
            V2IdentifyTableScoreConfigVo v2IdentifyTableScoreConfigVo = req.getScoreConfig().get(0);
            if (v2IdentifyTableScoreConfigVo.getMin() == null) {
                throw new RuntimeException("第1项得分配置不正确");
            }
            if (v2IdentifyTableScoreConfigVo.getResult() == null) {
                throw new RuntimeException("第1项结果配置不正确");
            }
            V2IdentifyTableScoreConfigVo end = req.getScoreConfig().get(req.getScoreConfig().size() - 1);
            if (end.getMax() == null) {
                throw new RuntimeException("最后一项得分配置不正确");
            }
            if (end.getResult() == null) {
                throw new RuntimeException("最后一项结果配置不正确");
            }
            for (int i = 0; i < req.getScoreConfig().size(); i++) {
                V2IdentifyTableScoreConfigVo vo = req.getScoreConfig().get(i);
                if (StringUtils.isEmpty(vo.getLevelName())) {
                    throw new RuntimeException("第" + (i + 1) + "项评级名称不能为空");
                }
                if (vo.getLevelName().length() > 5) {
                    throw new RuntimeException("第" + (i + 1) + "项评级名称不能超过5个字符");
                }
            }
        }
        if (CollUtil.isEmpty(req.getIdentifyItemList())) {
            throw new RuntimeException("鉴定项不能为空");
        }
        for (V2IdentifyItemsSaveReq items : req.getIdentifyItemList()) {
            if (StringUtils.isEmpty(items.getName())) {
                throw new RuntimeException("鉴定项名称不能为空");
            }
            if (StringUtils.isEmpty(items.getCateId())) {
                throw new RuntimeException("鉴定项分类不能是空");
            }
            if (StringUtils.isEmpty(items.getPoolId())) {
                throw new RuntimeException("鉴定项poolId不能是空");
            }
        }

        // 校验鉴定项是否有重复（除id、poolId、sortCode外全部相同）
        Set<String> itemKeys = new HashSet<>();
        for (int i = 0; i < req.getIdentifyItemList().size(); i++) {
            V2IdentifyItemsSaveReq items = req.getIdentifyItemList().get(i);
            // 构建唯一键：name + cateId + type + score + minScore + maxScore
            String key = buildItemUniqueKey(items);
            if (itemKeys.contains(key)) {
                throw new RuntimeException("第" + (i + 1) + "项鉴定项与前面的鉴定项重复（名称、分类、类型、分值等全部相同）");
            }
            itemKeys.add(key);
        }

    }


    @Override
    @Transactional
    public void updateData(String tableId, V2IdentifyTableSaveReq req) {
        preCheck(req);
        String userId = UserProvider.getUser().getUserId();
        CultivateIdentifyTable table = this.cultivateIdentifyTableMapper.selectById(tableId);
        if (table == null || table.getDeleteMark() == 1) {
            throw new RuntimeException("鉴定表不存在或者已经被删除");
        }
        // 检查课程名称是否与其他课程重复
        LambdaQueryWrapper<CultivateIdentifyTable> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(CultivateIdentifyTable::getName, req.getName());
        queryWrapper.ne(CultivateIdentifyTable::getId, tableId); // 排除当前课程
        queryWrapper.eq(CultivateIdentifyTable::getDeleteMark, 0); // 只检查有效的课程
        long count = cultivateIdentifyTableMapper.selectCount(queryWrapper);
        if (count > 0) {
            throw new RuntimeException("名称不能重复");
        }

        CultivateIdentifyTable tableSave = CultivateIdentifyTable.builder()
                .name(req.getName())
                .ruleDesc(req.getRuleDesc())
                .passType(req.getPassType())
                .passScore(req.getPassScore())
                .excellentType(req.getExcellentType())
                .excellentScore(req.getExcellentScore())
                .coverId(req.getCoverId())
                .coverUrl(req.getCoverUrl())
                .labelId(req.getLabelId())
                .scoreType(req.getScoreType())
                .certificateId(req.getCertificateId())
                .isAbnormal(IdentifyItemExceptionEnum.NORMAL.getCode())
                .scoreConfig(CollUtil.isNotEmpty(req.getScoreConfig()) ? JSON.toJSONString(req.getScoreConfig()) : "").build();
        tableSave.setLastModifyTime(new Date());
        tableSave.setLastModifyUserId(userId);
        tableSave.setTenantId(UserProvider.getUser().getTenantId());
        tableSave.setDeleteMark(0);
        tableSave.setId(tableId);
        cultivateIdentifyTableMapper.updateById(tableSave);
        itemsService.remove(new LambdaUpdateWrapper<CultivateIdentifyItems>().eq(CultivateIdentifyItems::getTableId, tableId));
        //批量新增鉴定项
        addIdentifyItemsData(req, tableSave.getId());
    }

    /**
     * 鉴定表/删除
     *
     * @param tableId 帅选条件
     */
    @Override
    @Transactional
    public void deleteData(String tableId) {
        CultivateIdentifyTable table = this.cultivateIdentifyTableMapper.selectById(tableId);
        if (table == null || table.getDeleteMark() == 1) {
            throw new RuntimeException("鉴定表不存在或者已经被删除");
        }
        table.setDeleteMark(1);
        cultivateIdentifyTableMapper.updateById(table);

        this.itemsService.update(new CultivateIdentifyItems(), new LambdaUpdateWrapper<CultivateIdentifyItems>()
                .eq(CultivateIdentifyItems::getTableId, tableId)
                .eq(CultivateIdentifyItems::getDeleteMark, 1)
        );
    }

    @Override
    @Transactional
    public void importData(V2IdentifyTableImportSaveReq req) {
        String userId = UserProvider.getUser().getUserId();
        FtbCultivateCoverInfoEntity ftbCultivateCoverInfoEntity = cultivateCoverInfoMapper.selectById("1");
        if (ftbCultivateCoverInfoEntity == null) {
            ftbCultivateCoverInfoEntity = new FtbCultivateCoverInfoEntity();
        }
        // 检查课程名称是否重复
        LambdaQueryWrapper<CultivateIdentifyTable> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(CultivateIdentifyTable::getName, req.getName())
                .eq(CultivateIdentifyTable::getDeleteMark, 0); // 只检查有效的课程
        long count = cultivateIdentifyTableMapper.selectCount(queryWrapper);
        if (count > 0) {
            throw new RuntimeException("鉴定表名称已经存在");
        }


        CultivateIdentifyTable tableSave = CultivateIdentifyTable.builder()
                .name(req.getName())
                .ruleId(SelfGrowthUtil.provideACustomIDBasedOnTheModule(SelfrowingEnum.IDENTIFY))
                .ruleDesc(req.getRuleDesc())
                .passType(req.getPassType())
                .passScore(req.getPassScore())
                .excellentType(req.getExcellentType())
                .excellentScore(req.getExcellentScore())
                .coverId(ftbCultivateCoverInfoEntity.getId())
                .coverUrl(ftbCultivateCoverInfoEntity.getPath())
                .labelId(req.getLabelId())
                .scoreType(req.getScoreType())
                .scoreConfig("").build();
        tableSave.setCreatorTime(new Date());
        tableSave.setLastModifyTime(new Date());
        tableSave.setCreatorUserId(userId);
        tableSave.setLastModifyUserId(userId);
        tableSave.setTenantId(UserProvider.getUser().getTenantId());
        tableSave.setDeleteMark(0);
        cultivateIdentifyTableMapper.insert(tableSave);
        //批量新增鉴定项
        List<CultivateIdentifyItems> batchSaveItemsList = new ArrayList<>();
        List<FtbCultivateIdentifyItemsPool> list = new ArrayList<>();
        List<FtbCultivateIdentifyItemsPool> dataList = ftbCultivateIdentifyItemsPoolService.listAll();
        Set<String> existNameList = new HashSet<>();
        Map<String, String> map = new HashMap<>();
        Map<String, FtbCultivateIdentifyItemsPool> oldItemMap = new HashMap<>();
        for (FtbCultivateIdentifyItemsPool identifyItemsPool : dataList) {
            String s = CultivateIdentityUtil.buildRepeatKey(identifyItemsPool);
            existNameList.add(s);
            map.put(s, identifyItemsPool.getId());
            oldItemMap.put(s, identifyItemsPool);
        }
        for (V2IdentifyItemsImportSaveReq items : req.getIdentifyItemList()) {
            String itemCombine = CultivateIdentityUtil.buildRepeatKey(items);
            CultivateIdentifyItems identifyItems = CultivateIdentifyItems.builder()
                    .tableId(tableSave.getId())
                    .cateId(items.getCateId())
                    .name(items.getName())
                    .score(items.getScore())
                    .type(items.getType())
                    .minScore(items.getMinScore())
                    .maxScore(items.getMaxScore()).build();
            String poolId = map.get(itemCombine);
            if (StringUtils.isEmpty(poolId)) {
                poolId = UserApiV2Util.generateId();
                identifyItems.setBusinessId(SelfGrowthUtil.provideACustomIDBasedOnTheModule(SelfrowingEnum.ITEM_POOL));
            } else {
                FtbCultivateIdentifyItemsPool ftbCultivateIdentifyItemsPool = oldItemMap.get(itemCombine);
                if (ftbCultivateIdentifyItemsPool != null) {
                    identifyItems.setBusinessId(ftbCultivateIdentifyItemsPool.getBusinessId());
                }
            }
            identifyItems.setPoolId(poolId);
            batchSaveItemsList.add(identifyItems);
            if (existNameList.contains(itemCombine)) {
                continue;
            }
            list.add(buildFtbCultivateIdentifyItemsPool(items, userId, identifyItems));
        }
        if (CollUtil.isNotEmpty(batchSaveItemsList)) {
            this.itemsService.saveBatch(batchSaveItemsList);
        }

        if (CollUtil.isNotEmpty(list)) {
            this.ftbCultivateIdentifyItemsPoolService.saveBatch(list);
        }

    }

    @Override
    public long queryByTableName(String tableName) {
        LambdaQueryWrapper<CultivateIdentifyTable> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(CultivateIdentifyTable::getName, tableName)
                .eq(CultivateIdentifyTable::getDeleteMark, 0); // 只检查有效的课程
        return cultivateIdentifyTableMapper.selectCount(queryWrapper);
    }

    @Override
    public List<V2CateIdentifyTableVo> getTableForCate() {
        List<V2CateIdentifyTableVo> ret = new ArrayList<>();
        List<FtbCultivateLabelVo> labelVoList = ftbCultivateLabelService.getList(2, 0);

        ret.add(V2CateIdentifyTableVo.builder().id("1").name("未设置分类").build());
        buildRet(ret, labelVoList);
        LambdaQueryWrapper<CultivateIdentifyTable> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper
                .select(CultivateIdentifyTable::getId, CultivateIdentifyTable::getName, CultivateIdentifyTable::getLabelId)
                .eq(CultivateIdentifyTable::getIsAbnormal, IdentifyItemExceptionEnum.NORMAL.getCode())
                .eq(CultivateIdentifyTable::getDeleteMark, 0); // 只检查有效的课程
        List<CultivateIdentifyTable> tables = cultivateIdentifyTableMapper.selectList(queryWrapper);
        Map<String, List<CultivateIdentifyTable>> map = new HashMap<>();
        if (CollUtil.isNotEmpty(tables)) {
            for (CultivateIdentifyTable table : tables) {
                String key = table.getLabelId();
                if (StringUtils.isEmpty(table.getLabelId())) {
                    key = "1";
                }
                List<CultivateIdentifyTable> list = map.get(key);
                if (CollUtil.isEmpty(list)) {
                    list = new ArrayList<>();
                    map.put(key, list);
                }
                list.add(table);
            }
        }
        for (V2CateIdentifyTableVo v2CateIdentifyTableVo : ret) {
            List<CultivateIdentifyTable> list = map.get(v2CateIdentifyTableVo.getId());
            v2CateIdentifyTableVo.setTableList(list);
        }
        return ret;


    }

    private void buildRet(List<V2CateIdentifyTableVo> ret, List<FtbCultivateLabelVo> labelVoList) {
        if (CollUtil.isEmpty(labelVoList)) {
            return;
        }
        for (FtbCultivateLabelVo labelVo : labelVoList) {
            ret.add(V2CateIdentifyTableVo.builder().id(labelVo.getId()).name(labelVo.getName()).build());
        }
    }

    @NotNull
    private static FtbCultivateIdentifyItemsPool buildFtbCultivateIdentifyItemsPool(V2IdentifyItemsImportSaveReq items, String userId, CultivateIdentifyItems identifyItems) {
        FtbCultivateIdentifyItemsPool entity = new FtbCultivateIdentifyItemsPool();
        entity.setName(items.getName());
        entity.setCateId(items.getCateId());
        entity.setType(items.getType());
        if (items.getType().equals(AppraisalScoreTypeEnum.FIXED.getCode())) {
            entity.setTotalScore(items.getScore().intValue());
        } else {
            entity.setMinScore(items.getMinScore());
            entity.setMaxScore(items.getMaxScore());
        }
        entity.setEnabledMark(0);
        entity.setCreatorTime(new Date());
        entity.setCreatorUserId(userId);
        entity.setLastModifyTime(new Date());
        entity.setLastModifyUserId(userId);
        entity.setId(identifyItems.getPoolId());
        entity.setBusinessId(identifyItems.getBusinessId());
        return entity;
    }

    /**
     * 构建鉴定项唯一键（用于检测重复）
     *
     * @param items 鉴定项
     * @return 唯一键字符串
     */
    private String buildItemUniqueKey(V2IdentifyItemsSaveReq items) {
        // 将所有字段拼接成唯一键，使用特殊分隔符避免冲突
        // 排除 poolId 和 sortCode
        // 根据分值类型决定比较字段：0-固定分比较score，1-浮动分比较minScore和maxScore
        StringBuilder sb = new StringBuilder();
        sb.append(items.getName() != null ? items.getName() : "")
                .append("|")
                .append(items.getType() != null ? items.getType() : "");

        // 根据分值类型添加对应的分值字段
        if (items.getType() != null && items.getType() == 0) {
            // 固定分：只比较score
            sb.append("|").append(items.getScore() != null ? items.getScore().toString() : "");
        } else {
            // 浮动分：比较minScore和maxScore
            sb.append("|").append(items.getMinScore() != null ? items.getMinScore().toString() : "")
                    .append("|").append(items.getMaxScore() != null ? items.getMaxScore().toString() : "");
        }

        return sb.toString();
    }

}
