package com.ruoyi.ccdi.project.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.ccdi.project.domain.CcdiModelParam;
import com.ruoyi.ccdi.project.domain.CcdiProject;
import com.ruoyi.ccdi.project.domain.dto.ModelParamQueryDTO;
import com.ruoyi.ccdi.project.domain.dto.ModelParamSaveDTO;
import com.ruoyi.ccdi.project.domain.dto.ModelParamSaveAllDTO;
import com.ruoyi.ccdi.project.domain.dto.ModelParamGroupDTO;
import com.ruoyi.ccdi.project.domain.dto.ParamValueItem;
import com.ruoyi.ccdi.project.domain.vo.ModelListVO;
import com.ruoyi.ccdi.project.domain.vo.ModelParamVO;
import com.ruoyi.ccdi.project.domain.vo.ModelParamAllVO;
import com.ruoyi.ccdi.project.domain.vo.ModelGroupVO;
import com.ruoyi.ccdi.project.mapper.CcdiModelParamMapper;
import com.ruoyi.ccdi.project.mapper.CcdiProjectMapper;
import com.ruoyi.ccdi.project.domain.enums.TriggerType;
import com.ruoyi.ccdi.project.service.ICcdiBankTagService;
import com.ruoyi.ccdi.project.service.ICcdiModelParamService;
import com.ruoyi.ccdi.project.service.ICcdiProjectService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import jakarta.annotation.Resource;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 模型参数Service实现
 */
@Service
public class CcdiModelParamServiceImpl implements ICcdiModelParamService {

    private static final Logger log = LoggerFactory.getLogger(CcdiModelParamServiceImpl.class);

    @Resource
    private CcdiModelParamMapper modelParamMapper;

    @Resource
    private CcdiProjectMapper projectMapper;

    @Resource
    private ICcdiProjectService projectService;

    @Resource
    @Lazy
    private ICcdiBankTagService bankTagService;

    @Override
    public List<ModelListVO> selectModelList(Long projectId) {
        log.info("selectModelList 被调用，projectId={}", projectId);
        Long effectiveProjectId = resolveEffectiveProjectId(projectId, false);

        log.info("准备查询模型列表，effectiveProjectId={}", effectiveProjectId);
        List<ModelListVO> result = new ArrayList<>();
        List<CcdiModelParam> params = modelParamMapper.selectDistinctModels(effectiveProjectId);
        log.info("查询到 {} 个模型", params.size());

        params.forEach(param -> {
            ModelListVO vo = new ModelListVO();
            vo.setModelCode(param.getModelCode());
            vo.setModelName(param.getModelName());
            result.add(vo);
        });

        return result;
    }

    @Override
    public List<ModelParamVO> selectParamList(ModelParamQueryDTO queryDTO) {
        Long effectiveProjectId = resolveEffectiveProjectId(queryDTO.getProjectId(), true);
        List<CcdiModelParam> params = modelParamMapper.selectByProjectAndModel(
            effectiveProjectId,
            queryDTO.getModelCode()
        );

        List<ModelParamVO> result = new ArrayList<>();
        params.forEach(param -> {
            ModelParamVO vo = new ModelParamVO();
            BeanUtils.copyProperties(param, vo);
            result.add(vo);
        });

        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveParams(ModelParamSaveDTO saveDTO) {
        try {
            // 1. 参数验证
            if (saveDTO.getProjectId() == null) {
                throw new ServiceException("项目ID不能为空");
            }
            if (StringUtils.isBlank(saveDTO.getModelCode())) {
                throw new ServiceException("模型编码不能为空");
            }
            if (saveDTO.getParams() == null || saveDTO.getParams().isEmpty()) {
                throw new ServiceException("参数列表不能为空");
            }

            Long projectId = saveDTO.getProjectId();

            if (projectId > 0) {
                projectService.ensureProjectNotArchived(projectId, "已归档项目暂不允许修改参数");
                projectService.ensureProjectWritable(projectId, "当前项目正在进行银行流水打标，暂不允许修改参数");
                switchToCustomConfigIfNeeded(getRequiredProject(projectId));
            }

            String username = SecurityUtils.getUsername();
            int updatedCount = 0;
            for (ModelParamSaveDTO.ParamValueItem item : saveDTO.getParams()) {
                int updated = modelParamMapper.updateParamValue(
                    projectId,
                    saveDTO.getModelCode(),
                    item.getParamCode(),
                    item.getParamValue(),
                    username
                );
                if (updated == 0) {
                    log.warn("参数不存在或未更新，paramCode={}", item.getParamCode());
                    continue;
                }
                updatedCount += updated;
            }

            submitAutoRebuildIfNeeded(projectId, updatedCount);
        } catch (ServiceException e) {
            // 业务异常，直接抛出
            throw e;
        } catch (Exception e) {
            // 系统异常，记录日志并抛出
            log.error("保存模型参数失败", e);
            throw new ServiceException("保存模型参数失败：" + e.getMessage());
        }
    }

    @Override
    public ModelParamAllVO selectAllParams(Long projectId) {
        Long effectiveProjectId = resolveEffectiveProjectId(projectId, true);
        List<CcdiModelParam> allParams = modelParamMapper.selectByProjectId(effectiveProjectId);

        Map<String, List<CcdiModelParam>> groupedParams = allParams.stream()
            .collect(Collectors.groupingBy(CcdiModelParam::getModelCode, LinkedHashMap::new, Collectors.toList()));

        ModelParamAllVO result = new ModelParamAllVO();
        List<ModelGroupVO> models = new ArrayList<>();

        groupedParams.forEach((modelCode, params) -> {
            ModelGroupVO groupVO = new ModelGroupVO();
            groupVO.setModelCode(modelCode);
            groupVO.setModelName(params.get(0).getModelName());

            List<ModelParamVO> paramVOs = params.stream()
                .map(param -> {
                    ModelParamVO vo = new ModelParamVO();
                    BeanUtils.copyProperties(param, vo);
                    return vo;
                })
                .collect(Collectors.toList());

            groupVO.setParams(paramVOs);
            models.add(groupVO);
        });

        models.sort(Comparator.comparing(ModelGroupVO::getModelCode));

        result.setModels(models);
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveAllParams(ModelParamSaveAllDTO saveAllDTO) {
        try {
            // 1. 参数验证
            if (saveAllDTO.getProjectId() == null) {
                throw new ServiceException("项目ID不能为空");
            }
            if (saveAllDTO.getModels() == null || saveAllDTO.getModels().isEmpty()) {
                throw new ServiceException("参数列表不能为空");
            }

            Long projectId = saveAllDTO.getProjectId();

            if (projectId > 0) {
                projectService.ensureProjectNotArchived(projectId, "已归档项目暂不允许修改参数");
                projectService.ensureProjectWritable(projectId, "当前项目正在进行银行流水打标，暂不允许修改参数");
                switchToCustomConfigIfNeeded(getRequiredProject(projectId));
            }

            String username = SecurityUtils.getUsername();
            List<CcdiModelParam> updateList = new ArrayList<>();

            for (ModelParamGroupDTO modelGroup : saveAllDTO.getModels()) {
                for (ParamValueItem item : modelGroup.getParams()) {
                    CcdiModelParam existingParam = modelParamMapper.selectOne(
                        new LambdaQueryWrapper<CcdiModelParam>()
                            .eq(CcdiModelParam::getProjectId, projectId)
                            .eq(CcdiModelParam::getModelCode, modelGroup.getModelCode())
                            .eq(CcdiModelParam::getParamCode, item.getParamCode())
                    );

                    if (existingParam != null) {
                        existingParam.setParamValue(item.getParamValue());
                        existingParam.setUpdateBy(username);
                        updateList.add(existingParam);
                    } else {
                        log.warn("参数不存在，无法更新， modelCode={}, paramCode={}",
                            modelGroup.getModelCode(), item.getParamCode());
                    }
                }
            }

            if (!updateList.isEmpty()) {
                modelParamMapper.batchUpdateParamValues(updateList);
                log.info("批量更新参数成功， count={}", updateList.size());
                submitAutoRebuildIfNeeded(projectId, updateList.size());
            }
        } catch (ServiceException e) {
            throw e;
        } catch (Exception e) {
            log.error("批量保存模型参数失败", e);
            throw new ServiceException("批量保存模型参数失败：" + e.getMessage());
        }
    }

    private Long resolveEffectiveProjectId(Long projectId, boolean failWhenProjectMissing) {
        if (projectId == null || projectId <= 0) {
            return 0L;
        }

        CcdiProject project = projectMapper.selectById(projectId);
        log.info("查询到项目信息: projectId={}, configType={}", projectId,
            project != null ? project.getConfigType() : "null");

        if (project == null) {
            if (failWhenProjectMissing) {
                throw new ServiceException("项目不存在");
            }
            return projectId;
        }

        return "default".equals(project.getConfigType()) ? 0L : projectId;
    }

    private CcdiProject getRequiredProject(Long projectId) {
        CcdiProject project = projectMapper.selectById(projectId);
        if (project == null) {
            throw new ServiceException("项目不存在");
        }
        return project;
    }

    private void switchToCustomConfigIfNeeded(CcdiProject project) {
        if (!"default".equals(project.getConfigType())) {
            return;
        }

        int copiedCount = copyAllDefaultParamsToProject(project.getProjectId());
        if (copiedCount == 0) {
            log.warn("系统默认参数为空，projectId={}", project.getProjectId());
            return;
        }

        project.setConfigType("custom");
        projectMapper.updateById(project);
        log.info("项目配置类型已更新为 custom，projectId={}", project.getProjectId());
    }

    private int copyAllDefaultParamsToProject(Long projectId) {
        List<CcdiModelParam> defaultParams = modelParamMapper.selectByProjectId(0L);
        if (defaultParams.isEmpty()) {
            return 0;
        }

        String username = SecurityUtils.getUsername();
        List<CcdiModelParam> projectParams = defaultParams.stream()
            .map(param -> buildProjectParam(param, projectId, username))
            .collect(Collectors.toList());

        int count = modelParamMapper.insertBatch(projectParams);
        log.info("复制所有系统默认参数到项目成功，projectId={}, count={}", projectId, count);
        return count;
    }

    private CcdiModelParam buildProjectParam(CcdiModelParam source, Long projectId, String username) {
        CcdiModelParam target = new CcdiModelParam();
        BeanUtils.copyProperties(source, target);
        target.setId(null);
        target.setProjectId(projectId);
        target.setCreateBy(username);
        target.setUpdateBy(username);
        return target;
    }

    private void submitAutoRebuildIfNeeded(Long projectId, int updatedCount) {
        if (projectId == null || projectId <= 0 || updatedCount <= 0) {
            return;
        }

        bankTagService.submitAutoRebuild(projectId, TriggerType.AUTO_PARAM_CHANGE);
        log.info("项目参数保存成功，已触发流水自动重打标: projectId={}, updatedCount={}", projectId, updatedCount);
    }
}
