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

import com.alibaba.fastjson2.JSON;
import com.ruoyi.ccdi.project.domain.entity.CcdiProjectOverviewEmployeeResult;
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectOverviewEmployeeHitRowVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectOverviewEmployeeModelSummaryVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectOverviewEmployeeRuleSummaryVO;
import org.springframework.stereotype.Component;

import java.util.Comparator;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 结果总览员工结果构建器
 */
@Component
public class CcdiProjectOverviewEmployeeResultBuilder {

    /**
     * 按员工归并命中明细并构建结果表实体
     *
     * @param projectId 项目ID
     * @param hitRows 命中明细
     * @param operator 操作人
     * @return 结果表实体列表
     */
    public List<CcdiProjectOverviewEmployeeResult> build(Long projectId,
                                                         List<CcdiProjectOverviewEmployeeHitRowVO> hitRows,
                                                         String operator) {
        if (hitRows == null || hitRows.isEmpty()) {
            return List.of();
        }

        Date now = new Date();
        return hitRows.stream()
            .filter(item -> isNotBlank(item.getStaffIdCard()))
            .collect(Collectors.groupingBy(
                CcdiProjectOverviewEmployeeHitRowVO::getStaffIdCard,
                LinkedHashMap::new,
                Collectors.toList()
            ))
            .entrySet()
            .stream()
            .sorted(Map.Entry.comparingByKey())
            .map(entry -> buildSingleResult(projectId, entry.getKey(), entry.getValue(), operator, now))
            .toList();
    }

    private CcdiProjectOverviewEmployeeResult buildSingleResult(Long projectId,
                                                                String staffIdCard,
                                                                List<CcdiProjectOverviewEmployeeHitRowVO> staffRows,
                                                                String operator,
                                                                Date now) {
        List<CcdiProjectOverviewEmployeeRuleSummaryVO> ruleSummaries = buildRuleSummaries(staffRows);
        List<CcdiProjectOverviewEmployeeModelSummaryVO> modelSummaries = buildModelSummaries(staffRows);

        CcdiProjectOverviewEmployeeResult result = new CcdiProjectOverviewEmployeeResult();
        result.setProjectId(projectId);
        result.setStaffIdCard(staffIdCard);
        result.setStaffName(firstNonBlank(staffRows, CcdiProjectOverviewEmployeeHitRowVO::getStaffName));
        result.setStaffCode(firstNonBlank(staffRows, CcdiProjectOverviewEmployeeHitRowVO::getStaffCode));
        result.setDeptId(firstNonNull(staffRows, CcdiProjectOverviewEmployeeHitRowVO::getDeptId));
        result.setDeptName(firstNonBlank(staffRows, CcdiProjectOverviewEmployeeHitRowVO::getDeptName));
        result.setRuleCount(ruleSummaries.size());
        result.setModelCount(modelSummaries.size());
        result.setHitCount(staffRows.size());
        result.setRiskLevelCode(resolveRiskLevelCode(ruleSummaries.size()));
        result.setRiskPoint(ruleSummaries.stream()
            .map(CcdiProjectOverviewEmployeeRuleSummaryVO::getRuleName)
            .filter(this::isNotBlank)
            .collect(Collectors.joining("、")));
        result.setModelCodesCsv(modelSummaries.stream()
            .map(CcdiProjectOverviewEmployeeModelSummaryVO::getModelCode)
            .collect(Collectors.joining(",")));
        result.setModelNamesJson(JSON.toJSONString(modelSummaries.stream()
            .map(CcdiProjectOverviewEmployeeModelSummaryVO::getModelName)
            .toList()));
        result.setHitRulesJson(JSON.toJSONString(ruleSummaries));
        result.setModelHitSummaryJson(JSON.toJSONString(modelSummaries));
        result.setCreateBy(operator);
        result.setCreateTime(now);
        result.setUpdateBy(operator);
        result.setUpdateTime(now);
        return result;
    }

    private List<CcdiProjectOverviewEmployeeRuleSummaryVO> buildRuleSummaries(
        List<CcdiProjectOverviewEmployeeHitRowVO> staffRows
    ) {
        return staffRows.stream()
            .collect(Collectors.groupingBy(
                CcdiProjectOverviewEmployeeHitRowVO::getRuleCode,
                LinkedHashMap::new,
                Collectors.toList()
            ))
            .values()
            .stream()
            .map(rows -> {
                CcdiProjectOverviewEmployeeRuleSummaryVO summary = new CcdiProjectOverviewEmployeeRuleSummaryVO();
                CcdiProjectOverviewEmployeeHitRowVO first = rows.getFirst();
                summary.setModelCode(first.getModelCode());
                summary.setRuleCode(first.getRuleCode());
                summary.setRuleName(first.getRuleName());
                summary.setRiskLevel(first.getRiskLevel());
                summary.setWarningCount(rows.size());
                return summary;
            })
            .sorted(Comparator.comparing(CcdiProjectOverviewEmployeeRuleSummaryVO::getWarningCount).reversed()
                .thenComparing(CcdiProjectOverviewEmployeeRuleSummaryVO::getRuleCode))
            .toList();
    }

    private List<CcdiProjectOverviewEmployeeModelSummaryVO> buildModelSummaries(
        List<CcdiProjectOverviewEmployeeHitRowVO> staffRows
    ) {
        return staffRows.stream()
            .collect(Collectors.groupingBy(
                CcdiProjectOverviewEmployeeHitRowVO::getModelCode,
                LinkedHashMap::new,
                Collectors.toList()
            ))
            .values()
            .stream()
            .map(rows -> {
                CcdiProjectOverviewEmployeeModelSummaryVO summary = new CcdiProjectOverviewEmployeeModelSummaryVO();
                CcdiProjectOverviewEmployeeHitRowVO first = rows.getFirst();
                summary.setModelCode(first.getModelCode());
                summary.setModelName(first.getModelName());
                summary.setWarningCount(rows.size());
                return summary;
            })
            .sorted(Comparator.comparing(CcdiProjectOverviewEmployeeModelSummaryVO::getModelCode))
            .toList();
    }

    private String resolveRiskLevelCode(int ruleCount) {
        if (ruleCount >= 5) {
            return "HIGH";
        }
        if (ruleCount >= 2) {
            return "MEDIUM";
        }
        return "LOW";
    }

    private String firstNonBlank(List<CcdiProjectOverviewEmployeeHitRowVO> staffRows,
                                 java.util.function.Function<CcdiProjectOverviewEmployeeHitRowVO, String> getter) {
        return staffRows.stream()
            .map(getter)
            .filter(this::isNotBlank)
            .findFirst()
            .orElse(null);
    }

    private <T> T firstNonNull(List<CcdiProjectOverviewEmployeeHitRowVO> staffRows,
                               java.util.function.Function<CcdiProjectOverviewEmployeeHitRowVO, T> getter) {
        return staffRows.stream()
            .map(getter)
            .filter(Objects::nonNull)
            .findFirst()
            .orElse(null);
    }

    private boolean isNotBlank(String value) {
        return value != null && !value.isBlank();
    }
}
