package com.fs.project.service.impl;

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.fs.common.BeanCopyUtils;
import com.fs.common.config.LoginContextManager;
import com.fs.common.exception.ServiceException;
import com.fs.common.utils.StringUtils;
import com.fs.doctor.domain.Doctor;
import com.fs.doctor.domain.DoctorLevel;
import com.fs.doctor.domain.DoctorLevelData;
import com.fs.doctor.mapper.DoctorLevelDataMapper;
import com.fs.doctor.mapper.DoctorLevelMapper;
import com.fs.doctor.mapper.DoctorMapper;
import com.fs.project.domain.LevelRule;
import com.fs.project.domain.Project;
import com.fs.project.domain.ProjectStandard;
import com.fs.project.mapper.ProjectMapper;
import com.fs.project.mapper.ProjectStandardMapper;
import com.fs.project.service.IProjectStandardService;
import com.fs.project.vo.CompanyIntegralRangesReqParams;
import com.fs.project.vo.DoctorIntegralRangeDTO;
import com.fs.project.vo.ProjectStandardDTO;
import com.fs.project.vo.ProjectStandardVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

@Service
public class ProjectStandardServiceImpl implements IProjectStandardService {

    @Autowired
    private ProjectStandardMapper projectStandardMapper;
    @Autowired
    private ProjectMapper projectMapper;
    @Autowired
    private DoctorLevelMapper doctorLevelMapper;
    @Lazy
    @Autowired
    private DoctorMapper doctorMapper;
    @Lazy
    @Autowired
    private DoctorLevelDataMapper doctorLevelDataMapper;

    // ------------------ 原有方法（保持原样，但 Mapper XML 已改，自动适配）------------------
    @Override
    public List<ProjectStandard> selectProjectStandardList(ProjectStandard projectStandard) {
        return projectStandardMapper.selectProjectStandardList(projectStandard);
    }

    @Override
    public ProjectStandard selectProjectStandardById(Long id) {
        return projectStandardMapper.selectProjectStandardById(id);
    }

    @Override
    public ProjectStandard selectProjectStandardByCompanyId(Long companyId) {
        ProjectStandard param = new ProjectStandard();
        param.setCompanyId(companyId);
        List<ProjectStandard> list = projectStandardMapper.selectProjectStandardList(param);
        return list.isEmpty() ? null : list.get(0);
    }

    @Override
    public ProjectStandard selectProjectStandardByCompanyIdAndProjectType(Long currentCompanyId, String projectType) {
        // 非空判断：如果公司ID为空或项目类型为空/空白，直接返回null
        if (currentCompanyId == null || StringUtils.isBlank(projectType)) {
            return null;
        }
        ProjectStandard param = new ProjectStandard();
        param.setCompanyId(currentCompanyId);
        param.setProjectType(projectType);
        List<ProjectStandard> list = projectStandardMapper.selectProjectStandardList(param);
        return list.isEmpty() ? null : list.get(0);
    }

    @Override
    public int insertProjectStandard(ProjectStandard projectStandard) {
        return projectStandardMapper.insertProjectStandard(projectStandard);
    }

    @Override
    public int updateProjectStandard(ProjectStandard projectStandard) {
        return projectStandardMapper.updateProjectStandard(projectStandard);
    }

    @Override
    public int deleteProjectStandardByIds(Long[] ids) {
        return projectStandardMapper.deleteProjectStandardByIds(ids);
    }

    // ------------------ 新增方法（支持动态级别）------------------
    @Override
    public ProjectStandardVO getDetailVo(Long id) {
        ProjectStandard entity = this.selectProjectStandardById(id);
        if (entity == null) return null;
        // BeanCopyUtils 会自动调用 VO 的 setLevelConfig 方法
        return BeanCopyUtils.copy(entity, ProjectStandardVO.class);
    }

    @Override
    public List<ProjectStandardVO> listVo(ProjectStandard query) {
        List<ProjectStandard> list = this.selectProjectStandardList(query);
        // 利用 VO 的 setLevelConfig 自动转换 JSON
        return BeanCopyUtils.copyList(list, ProjectStandardVO.class);
    }

    @Override
    @Transactional
    public void saveOrUpdate(ProjectStandardDTO dto) {
        ProjectStandard entity = new ProjectStandard();
        // 拷贝基本属性
        BeanCopyUtils.copy(dto, entity);

        // 关键：List<LevelRule> → JSON 字符串
        if (dto.getLevelConfigList() != null) {
            entity.setLevelConfig(JSONUtil.toJsonStr(dto.getLevelConfigList()));
        }

        if (dto.getId() == null) {
            projectStandardMapper.insertProjectStandard(entity);
        } else {
            projectStandardMapper.updateProjectStandard(entity);
        }
    }


    @Override
    public boolean getCompanyIntegralLimit(Long projectId, Long doctorId, Integer pointNum,Long taskType) {
        // 1. 基础参数校验
        if (projectId == null) {
            throw new ServiceException("项目ID不能为空");
        }
        if (doctorId == null) {
            throw new ServiceException("医生ID不能为空");
        }
        if (pointNum == null) {
            throw new ServiceException("积分数量不能为空");
        }
        if (taskType == null) {
            throw new ServiceException("任务类型不能为空");
        }


        // 2. 查询项目信息
        Project project = projectMapper.selectProjectById(projectId);
        if (project == null) {
            throw new ServiceException("项目不存在");
        }
        if (project.getProjectTypeId() == null) {
            throw new ServiceException("项目类型未配置");
        }
        Long projectTypeId = project.getProjectTypeId();

        // 3. 获取当前公司ID
        if (project.getCompanyId() == null) {
            throw new ServiceException("无法获取当前公司信息");
        }

        // 4. 获取公司项目标准配置
        ProjectStandard projectStandard = this.selectProjectStandardByCompanyIdAndProjectIdAndTaskType(
                project.getCompanyId() , projectId.toString(),taskType);
        if (projectStandard == null) {
            throw new ServiceException("公司未配置该项目类型的积分标准");
        }
        String levelConfig = projectStandard.getLevelConfig();
        if (levelConfig == null || levelConfig.isEmpty()) {
            throw new ServiceException("公司积分标准未配置级别规则");
        }

        // 5. 解析级别规则列表
        List<LevelRule> ruleList;
        try {
            ruleList = JSONUtil.parseArray(levelConfig).toList(LevelRule.class);
        } catch (Exception e) {
            throw new ServiceException("公司积分标准配置格式错误");
        }
        if (ruleList == null || ruleList.isEmpty()) {
            throw new ServiceException("公司积分标准至少需要配置一个级别");
        }

        //获取医生
        Doctor doctor = doctorMapper.selectDoctorById(doctorId);
        if (Objects.isNull(doctor)) {
            throw new ServiceException("医生信息不存在");

        }
        // 6. 获取医生级别
        DoctorLevel doctorLevel = doctorLevelMapper.selectDoctorLevelByDoctorId(doctor.getDoctorId());
        if (doctorLevel == null) {
            throw new ServiceException("医生级别信息不存在");
        }
        if (doctorLevel.getLevel() == null) {
            throw new ServiceException("医生级别未设置");
        }
        Integer level = doctorLevel.getLevel();

        // 7. 查找当前级别对应的具体规则（按 sort 字段匹配）
        LevelRule currentRule = ruleList.stream()
                .filter(rule -> level.equals(rule.getSort()))
                .findFirst()
                .orElseThrow(() -> new ServiceException(
                        String.format("当前医生级别（%d）未配置积分规则", level)));

        // 8. 判断积分是否在区间内（闭区间）
        if (pointNum < currentRule.getMin() || pointNum > currentRule.getMax()) {
            throw new ServiceException(String.format(
                    "积分数量需在 %d ~ %d 之间（当前级别：%s）",
                    currentRule.getMin(), currentRule.getMax(), currentRule.getName()));
        }

        // 全部校验通过
        return true;
    }

    private ProjectStandard selectProjectStandardByCompanyIdAndProjectIdAndTaskType(Long companyId, String projectId, Long taskType) {
        return projectStandardMapper.selectProjectStandardByCompanyIdAndProjectIdAndTaskType(companyId,projectId,taskType);
    }


    @Override
    public boolean getCompanyIntegralLimit(Long projectId, Long doctorId, Integer pointNum, Long companyId,Long taskType) {
        // 1. 基础参数校验
        if (projectId == null) {
            throw new ServiceException("项目ID不能为空");
        }
        if (doctorId == null) {
            throw new ServiceException("医生ID不能为空");
        }
        if (pointNum == null) {
            throw new ServiceException("积分数量不能为空");
        }
        if (taskType == null) {
            throw new ServiceException("任务类别不能为空");
        }

        // 2. 查询项目信息
        Project project = projectMapper.selectProjectById(projectId);
        if (project == null) {
            throw new ServiceException("项目不存在");
        }
        if (project.getProjectTypeId() == null) {
            throw new ServiceException("项目类型未配置");
        }
        Long projectTypeId = project.getProjectTypeId();

        // 3. 获取当前公司ID
        if (companyId == null) {
            throw new ServiceException("无法获取当前公司信息");
        }

        // 4. 获取公司项目标准配置
        ProjectStandard projectStandard = this.selectProjectStandardByCompanyIdAndProjectType(
                companyId, projectTypeId.toString());
        if (projectStandard == null) {
            throw new ServiceException("公司未配置该项目类型的积分标准");
        }
        String levelConfig = projectStandard.getLevelConfig();
        if (levelConfig == null || levelConfig.isEmpty()) {
            throw new ServiceException("公司积分标准未配置级别规则");
        }

        // 5. 解析级别规则列表
        List<LevelRule> ruleList;
        try {
            ruleList = JSONUtil.parseArray(levelConfig).toList(LevelRule.class);
        } catch (Exception e) {
            throw new ServiceException("公司积分标准配置格式错误");
        }
        if (ruleList == null || ruleList.isEmpty()) {
            throw new ServiceException("公司积分标准至少需要配置一个级别");
        }

        //获取医生
        Doctor doctor = doctorMapper.selectDoctorById(doctorId);
        if (Objects.isNull(doctor)) {
            throw new ServiceException("医生信息不存在");

        }
        // 6. 获取医生级别
        DoctorLevel doctorLevel = doctorLevelMapper.selectDoctorLevelByDoctorId(doctor.getDoctorId());
        if (doctorLevel == null) {
            throw new ServiceException("医生级别信息不存在");
        }
        if (doctorLevel.getLevel() == null) {
            throw new ServiceException("医生级别未设置");
        }
        Integer level = doctorLevel.getLevel();

        // 7. 查找当前级别对应的具体规则（按 sort 字段匹配）
        LevelRule currentRule = ruleList.stream()
                .filter(rule -> level.equals(rule.getSort()))
                .findFirst()
                .orElseThrow(() -> new ServiceException(
                        String.format("当前医生级别（%d）未配置积分规则", level)));

        // 8. 判断积分是否在区间内（闭区间）
        if (pointNum < currentRule.getMin() || pointNum > currentRule.getMax()) {
            throw new ServiceException(String.format(
                    "积分数量需在 %d ~ %d 之间（当前级别：%s）",
                    currentRule.getMin(), currentRule.getMax(), currentRule.getName()));
        }

        // 全部校验通过
        return true;
    }

    @Override
    public Boolean checkParseTaskTypes(ProjectStandardDTO dto) {
        ProjectStandard projectStandard = new ProjectStandard();
        projectStandard.setCompanyId(dto.getCompanyId());
        projectStandard.setProjectType(dto.getProjectType());
        projectStandard.setDelFlag(0);
        List<ProjectStandard> existingList = this.selectProjectStandardList(projectStandard);
        // 3. 将当前要添加的 taskTypes 解析为集合
        Set<String> newTaskTypesSet = parseTaskTypes(dto.getTaskTypes());
        // 4. 遍历已有规则，检查交集
        Set<String> conflictTaskTypes = new HashSet<>();
        for (ProjectStandard existing : existingList) {
            Set<String> existingSet = parseTaskTypes(existing.getTaskTypes());
            // 取交集
            existingSet.retainAll(newTaskTypesSet);
            if (!existingSet.isEmpty()) {
                conflictTaskTypes.addAll(existingSet);
            }
        }
        if (!conflictTaskTypes.isEmpty()) {
            throw new ServiceException("该项目任务类型已存在配置，请勿重复添加");
        }
        return true;
    }

    @Override
    public Boolean checkEditParseTaskTypes(ProjectStandardDTO dto) {
        if (dto.getId() == null) {
            throw  new ServiceException("ID不能为空");
        }
        if (StringUtils.isBlank(dto.getTaskTypes())) {
            throw  new ServiceException("任务类型不能为空");
        }
        ProjectStandard projectStandard = new ProjectStandard();
        projectStandard.setCompanyId(dto.getCompanyId());
        projectStandard.setProjectType(dto.getProjectType());
        projectStandard.setDelFlag(0);
        List<ProjectStandard> existingList = this.selectProjectStandardList(projectStandard);

        // 2. 排除当前编辑的记录
        existingList = existingList.stream()
                .filter(item -> !item.getId().equals(dto.getId()))
                .collect(Collectors.toList());

        Set<String> newTaskTypesSet = parseTaskTypes(dto.getTaskTypes());
        Set<String> conflictTaskTypes = new HashSet<>();

        for (ProjectStandard existing : existingList) {
            Set<String> existingSet = parseTaskTypes(existing.getTaskTypes());
            existingSet.retainAll(newTaskTypesSet);
            if (!existingSet.isEmpty()) {
                conflictTaskTypes.addAll(existingSet);
            }
        }

        if (!conflictTaskTypes.isEmpty()) {
            throw  new ServiceException("该项目任务类型已存在配置，请勿重复添加");
        }

        return true;
    }

    @Override
    public List<DoctorIntegralRangeDTO> getCompanyIntegralRanges(CompanyIntegralRangesReqParams companyIntegralRangesReqParams) {
        Long projectId = companyIntegralRangesReqParams.getProjectId();
        List<Long> doctorIds = companyIntegralRangesReqParams.getDoctorIds();
        Long companyId = companyIntegralRangesReqParams.getCompanyId();
        // 1. 参数校验
        if (projectId == null) {
            throw new ServiceException("项目ID不能为空");
        }
        if (CollectionUtils.isEmpty(doctorIds)) {
            throw new ServiceException("医生ID列表不能为空");
        }
        if (companyId == null) {
            throw new ServiceException("公司ID不能为空");
        }

        // 2. 查询项目，获取项目类型
        Project project = projectMapper.selectProjectById(projectId);
        if (project == null) {
            throw new ServiceException("项目不存在");
        }
        if (project.getProjectTypeId() == null) {
            throw new ServiceException("项目类型未配置");
        }
        Long projectTypeId = project.getProjectTypeId();

        // 3. 获取公司项目标准配置
        ProjectStandard projectStandard = this.selectProjectStandardByCompanyIdAndProjectType(
                companyId, projectTypeId.toString());
        if (projectStandard == null) {
            throw new ServiceException("公司未配置该项目类型的积分标准");
        }
        String levelConfig = projectStandard.getLevelConfig();
        if (StringUtils.isBlank(levelConfig)) {
            throw new ServiceException("公司积分标准未配置级别规则");
        }

        // 4. 解析级别规则列表，并构建规则Map（过滤掉sort为null的规则）
        List<LevelRule> ruleList;
        try {
            ruleList = JSONUtil.parseArray(levelConfig).toList(LevelRule.class);
        } catch (Exception e) {
            throw new ServiceException("公司积分标准配置格式错误");
        }
        if (CollectionUtils.isEmpty(ruleList)) {
            throw new ServiceException("公司积分标准至少需要配置一个级别");
        }
        // 过滤sort为null的规则，避免构建Map时抛出NPE
        Map<Integer, LevelRule> ruleMap = ruleList.stream()
                .filter(rule -> rule.getSort() != null)
                .collect(Collectors.toMap(
                        LevelRule::getSort,
                        Function.identity(),
                        (v1, v2) -> v1)); // 若有重复级别，保留第一个

        // 5. 批量查询医生基本信息（防御性处理：可能返回null）
        List<Doctor> doctors = Optional.ofNullable(doctorMapper.selectDoctorListByIds(doctorIds))
                .orElse(Collections.emptyList());
        if (doctors.size() != doctorIds.size()) {
            // 记录日志或抛异常，这里选择记录日志（根据业务决定是否抛出）
            throw new ServiceException("部分医生ID未查询到数据，请求IDs：" + doctorIds + "，实际返回：" + doctors.stream().map(Doctor::getId).collect(Collectors.toList()));
        }

        // 6. 批量查询医生级别信息（同样做防御性处理）
        List<String> existingDoctorIds = doctors.stream()
                .map(Doctor::getDoctorId)
                .collect(Collectors.toList());
        List<DoctorLevel> doctorLevels = Optional.ofNullable(doctorLevelMapper.selectDoctorLevelsByDoctorIds(existingDoctorIds))
                .orElse(Collections.emptyList());
        Map<String, DoctorLevel> doctorLevelMap = doctorLevels.stream()
                .filter(Objects::nonNull) // 过滤null元素
                .filter(dl -> dl.getDoctorId() != null) // 过滤doctorId为null的
                .collect(Collectors.toMap(
                        DoctorLevel::getDoctorId,
                        Function.identity(),
                        (v1, v2) -> v1));

        // 7. 查询医生级别名称映射（按sort获取levelName）
        DoctorLevelData queryParam = new DoctorLevelData();
        queryParam.setCompanyId(companyId);
        List<DoctorLevelData> doctorLevelDataList = Optional.ofNullable(
                        doctorLevelDataMapper.selectDoctorLevelDataList(queryParam))
                .orElse(Collections.emptyList());
        Map<Long, String> levelMap = doctorLevelDataList.stream()
                .filter(data -> data.getSort() != null && data.getLevelName() != null)
                .collect(Collectors.toMap(
                        DoctorLevelData::getSort,
                        DoctorLevelData::getLevelName,
                        (existing, replacement) -> existing));

        // 8. 组装结果
        List<DoctorIntegralRangeDTO> result = new ArrayList<>();
        for (Doctor doctor : doctors) {
            DoctorIntegralRangeDTO dto = new DoctorIntegralRangeDTO();
            dto.setDoctorId(doctor.getId());
            dto.setDoctorName(doctor.getDoctorName()); // 假设医生表有doctorName字段

            DoctorLevel doctorLevel = doctorLevelMap.get(doctor.getDoctorId());
            if (doctorLevel == null || doctorLevel.getLevel() == null) {
                dto.setAvailable(false);
                dto.setMessage("医生级别信息缺失");
                result.add(dto);
                continue;
            }
            Integer level = doctorLevel.getLevel(); // 已确保非null

            // 获取级别名称（先尝试从levelMap获取，但后面会用规则中的名称覆盖）
            // 根据原逻辑，实际使用的是规则名称，所以此行可以移除，但保留也无妨
            // dto.setLevelName(levelMap.get(level.longValue()));

            LevelRule rule = ruleMap.get(level);
            if (rule == null) {
                dto.setAvailable(false);
                dto.setMessage(String.format("医生级别(%d)未配置积分规则", level));
                result.add(dto);
                continue;
            }

            dto.setLevelName(rule.getName());
            dto.setMinIntegral(rule.getMin());
            dto.setMaxIntegral(rule.getMax());
            dto.setAvailable(true);
            dto.setMessage("可用");
            result.add(dto);
        }

        return result;
    }

    private Set<String> parseTaskTypes(String taskTypes) {
        if (StringUtils.isBlank(taskTypes)) {
            return new HashSet<>();
        }
        return new HashSet<>(Arrays.asList(taskTypes.split(",")));
    }



}
