package com.sundot.airport.web.controller.exam;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.sundot.airport.common.core.domain.entity.SysDept;
import com.sundot.airport.common.core.domain.entity.SysRole;
import com.sundot.airport.common.core.domain.model.LoginUser;
import com.sundot.airport.common.enums.RoleTypeEnum;
import com.sundot.airport.common.utils.SecurityUtils;
import com.sundot.airport.exam.common.HttpResult;
import com.sundot.airport.exam.common.service.QuesCatService;
import com.sundot.airport.exam.domain.DailyTask;
import com.sundot.airport.exam.domain.DailyTaskDetail;
import com.sundot.airport.exam.domain.QuesCat;
import com.sundot.airport.exam.mapper.DailyTaskDetailMapper;
import com.sundot.airport.exam.mapper.DailyTaskMapper;
import com.sundot.airport.system.domain.BaseCheckCategory;
import com.sundot.airport.system.mapper.SysDeptMapper;
import com.sundot.airport.system.service.IBaseCheckCategoryService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.sql.Date;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 抽问抽答错题分析 PC管理端接口（美兰4级架构）
 * 美兰组织架构：STATION（安检站）> BRIGADE（大队）> MANAGER（主管）> 班组
 *
 * 接口1: GET /wrong-analysis/pc-overview  总体问题分布（饼图），支持 scopeType/scopeId
 * 接口2: GET /wrong-analysis/pc-radar     问题分布对比（雷达图），支持 scopeType/scopeId
 *
 * scopeType 说明：
 *   STATION  - 全站（scopeId=安检站deptId，可选）
 *   BRIGADE  - 大队（scopeId=大队deptId）
 *   MANAGER  - 主管（scopeId=主管deptId）
 *   USER     - 个人（scopeId=userId）
 *   不传     - 按登录用户角色自动判断（与 app 端 /wrong-analysis 相同逻辑）
 *
 * pc-radar scopeType 对应 series 规则：
 *   STATION → 各大队各一条 series
 *   BRIGADE → 该大队下各主管各一条 series
 *   MANAGER → 单条主管 series
 *   USER    → 单条用户 series
 *   不传    → 站长：各大队 series；其他角色：show=false
 */
@RestController
@RequestMapping("/v1/cs/app/daily-exam/wrong-analysis")
public class DailyExamWrongAnalysisPcController {

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

    @Autowired
    private DailyTaskMapper dailyTaskMapper;

    @Autowired
    private DailyTaskDetailMapper dailyTaskDetailMapper;

    @Autowired
    private SysDeptMapper sysDeptMapper;

    @Autowired
    private QuesCatService quesCatService;

    @Autowired
    private IBaseCheckCategoryService baseCheckCategoryService;

    // =====================================================================
    // 接口1：总体问题分布（饼图）PC端
    // =====================================================================

    /**
     * 总体问题分布（按大类统计错题数）
     *
     * @param scopeType 统计范围：STATION/BRIGADE/MANAGER/USER，不传则按角色自动判断
     * @param scopeId   范围ID
     */
    @GetMapping("/pc-overview")
    public HttpResult<Map<String, Object>> getPcOverview(
            @RequestParam(required = false, defaultValue = "MONTH") String dateRangeQueryType,
            @RequestParam(required = false) Integer year,
            @RequestParam(required = false) Integer quarter,
            @RequestParam(required = false) Integer month,
            @RequestParam(required = false) String scopeType,
            @RequestParam(required = false) Long scopeId) {

        try {
            LocalDate[] range = resolveDateRange(dateRangeQueryType, year, quarter, month);
            List<DailyTaskDetail> errorDetails = getErrorDetailsByScope(scopeType, scopeId, range[0], range[1]);

            Map<String, BaseCheckCategory> qcIdToLevel1 = buildQcIdToLevel1Map(errorDetails);

            Map<Long, long[]> countByCategory = new LinkedHashMap<>();
            Map<Long, String> categoryNames = new LinkedHashMap<>();

            for (DailyTaskDetail detail : errorDetails) {
                BaseCheckCategory cat = qcIdToLevel1.get(detail.getDtdModuleId());
                if (cat != null) {
                    countByCategory.merge(cat.getId(),
                            new long[]{1, cat.getOrderNum() != null ? cat.getOrderNum() : 99},
                            (a, b) -> new long[]{a[0] + 1, a[1]});
                    categoryNames.put(cat.getId(), cat.getName());
                }
            }

            List<Map<String, Object>> categories = countByCategory.entrySet().stream()
                    .sorted(Comparator.comparingLong(e -> e.getValue()[1]))
                    .map(e -> {
                        Map<String, Object> item = new LinkedHashMap<>();
                        item.put("id", e.getKey());
                        item.put("name", categoryNames.get(e.getKey()));
                        item.put("count", e.getValue()[0]);
                        return item;
                    })
                    .collect(Collectors.toList());

            Map<String, Object> result = new LinkedHashMap<>();
            result.put("categories", categories);
            return HttpResult.success(result);

        } catch (Exception e) {
            log.error("获取总体问题分布失败(PC)", e);
            return HttpResult.error("获取总体问题分布失败：" + e.getMessage());
        }
    }

    // =====================================================================
    // 接口2：问题分布对比（雷达图）PC端
    // =====================================================================

    /**
     * 问题分布对比雷达图
     *
     * @param scopeType 统计范围：STATION/BRIGADE/MANAGER/USER，不传则按角色自动判断
     * @param scopeId   范围ID
     */
    @GetMapping("/pc-radar")
    public HttpResult<Map<String, Object>> getPcRadar(
            @RequestParam(required = false, defaultValue = "MONTH") String dateRangeQueryType,
            @RequestParam(required = false) Integer year,
            @RequestParam(required = false) Integer quarter,
            @RequestParam(required = false) Integer month,
            @RequestParam(required = false) String scopeType,
            @RequestParam(required = false) Long scopeId) {

        try {
            LocalDate[] range = resolveDateRange(dateRangeQueryType, year, quarter, month);

            // 查询所有大类作为雷达维度
            BaseCheckCategory level1Query = new BaseCheckCategory();
            level1Query.setLevel(1);
            List<BaseCheckCategory> level1Categories = baseCheckCategoryService.selectBaseCheckCategoryList(level1Query);
            level1Categories.sort(Comparator.comparingInt(c -> c.getOrderNum() != null ? c.getOrderNum() : 99));

            List<String> indicators = level1Categories.stream()
                    .map(BaseCheckCategory::getName).collect(Collectors.toList());
            List<Long> indicatorIds = level1Categories.stream()
                    .map(BaseCheckCategory::getId).collect(Collectors.toList());

            List<Map<String, Object>> series;

            if ("BRIGADE".equals(scopeType) && scopeId != null) {
                // 大队下各主管各一条 series
                series = buildRadarSeriesByManagersInBrigade(scopeId, range, indicatorIds);

            } else if ("MANAGER".equals(scopeType) && scopeId != null) {
                // 单条主管 series
                series = buildRadarSeriesForSingleManager(scopeId, range, indicatorIds);

            } else if ("USER".equals(scopeType) && scopeId != null) {
                // 单条用户 series
                series = buildRadarSeriesForSingleUser(scopeId, range, indicatorIds);

            } else {
                // STATION 或 role-based：各大队各一条 series
                Long stationDeptId = getStationDeptId(scopeType, scopeId);
                if (stationDeptId == null) {
                    Map<String, Object> noShow = new HashMap<>();
                    noShow.put("show", false);
                    return HttpResult.success(noShow);
                }
                series = buildRadarSeriesByBrigadesInStation(stationDeptId, range, indicatorIds);
            }

            Map<String, Object> result = new LinkedHashMap<>();
            result.put("show", true);
            result.put("indicators", indicators);
            result.put("series", series);
            return HttpResult.success(result);

        } catch (Exception e) {
            log.error("获取问题分布对比失败(PC)", e);
            return HttpResult.error("获取问题分布对比失败：" + e.getMessage());
        }
    }

    // =====================================================================
    // 私有工具方法
    // =====================================================================

    /**
     * 根据 scopeType/scopeId 获取错误明细
     */
    private List<DailyTaskDetail> getErrorDetailsByScope(String scopeType, Long scopeId,
                                                          LocalDate start, LocalDate end) {
        if ("MANAGER".equals(scopeType) && scopeId != null) {
            return getErrorDetailsByDepartmentId(scopeId, start, end);
        } else if ("USER".equals(scopeType) && scopeId != null) {
            return getErrorDetailsByUserId(scopeId, start, end);
        } else if ("BRIGADE".equals(scopeType) && scopeId != null) {
            return getErrorDetailsBySubDepts(scopeId, start, end);
        } else {
            // STATION 或 role-based
            Long deptId = getStationDeptId(scopeType, scopeId);
            if (deptId == null) {
                // 非站长，按角色判断
                RoleInfo role = getRoleInfo();
                if (role.isBrigade) {
                    return getErrorDetailsBySubDepts(role.userDeptId, start, end);
                } else if (role.isKezhang) {
                    return getErrorDetailsByDepartmentId(role.userDeptId, start, end);
                } else {
                    return getErrorDetailsByDeptId(role.userDeptId, start, end);
                }
            }
            List<SysDept> subDepts = sysDeptMapper.selectChildrenDeptById(deptId);
            Set<Long> allDeptIds = new HashSet<>();
            allDeptIds.add(deptId);
            if (subDepts != null) subDepts.forEach(d -> allDeptIds.add(d.getDeptId()));
            return getErrorDetailsByDeptIds(allDeptIds, start, end);
        }
    }

    /**
     * 获取站级 deptId：
     * - scopeType=STATION → 取 scopeId（若有）或当前用户 deptId（需是站长角色）
     * - scopeType=null → 若当前用户是站长则取其 deptId，否则返回 null
     */
    private Long getStationDeptId(String scopeType, Long scopeId) {
        if ("STATION".equals(scopeType)) {
            if (scopeId != null) return scopeId;
            return SecurityUtils.getLoginUser().getDeptId();
        }
        RoleInfo role = getRoleInfo();
        if (role.isStation) return role.userDeptId;
        return null;
    }

    /**
     * 雷达图：站下各大队各一条 series
     */
    private List<Map<String, Object>> buildRadarSeriesByBrigadesInStation(
            Long stationDeptId, LocalDate[] range, List<Long> indicatorIds) {

        List<SysDept> subDepts = sysDeptMapper.selectChildrenDeptById(stationDeptId);
        List<SysDept> brigadeDepts = subDepts == null ? Collections.emptyList() :
                subDepts.stream()
                        .filter(d -> stationDeptId.equals(d.getParentId()) && "0".equals(d.getDelFlag()))
                        .collect(Collectors.toList());

        List<Map<String, Object>> series = new ArrayList<>();
        for (SysDept brigade : brigadeDepts) {
            List<DailyTaskDetail> details = getErrorDetailsBySubDepts(brigade.getDeptId(), range[0], range[1]);
            series.add(buildRadarSeriesItem(brigade.getDeptName(), brigade.getDeptId(), details, indicatorIds));
        }
        return series;
    }

    /**
     * 雷达图：大队下各主管各一条 series
     */
    private List<Map<String, Object>> buildRadarSeriesByManagersInBrigade(
            Long brigadeId, LocalDate[] range, List<Long> indicatorIds) {

        List<SysDept> subDepts = sysDeptMapper.selectChildrenDeptById(brigadeId);
        List<SysDept> managerDepts = subDepts == null ? Collections.emptyList() :
                subDepts.stream()
                        .filter(d -> brigadeId.equals(d.getParentId()) && "0".equals(d.getDelFlag()))
                        .collect(Collectors.toList());

        List<Map<String, Object>> series = new ArrayList<>();
        for (SysDept manager : managerDepts) {
            List<DailyTaskDetail> details = getErrorDetailsByDepartmentId(manager.getDeptId(), range[0], range[1]);
            series.add(buildRadarSeriesItem(manager.getDeptName(), manager.getDeptId(), details, indicatorIds));
        }
        return series;
    }

    /**
     * 雷达图：单条主管 series
     */
    private List<Map<String, Object>> buildRadarSeriesForSingleManager(
            Long managerId, LocalDate[] range, List<Long> indicatorIds) {

        List<DailyTaskDetail> details = getErrorDetailsByDepartmentId(managerId, range[0], range[1]);
        String name = getManagerName(managerId);
        return Collections.singletonList(buildRadarSeriesItem(name, managerId, details, indicatorIds));
    }

    /**
     * 雷达图：单条用户 series
     */
    private List<Map<String, Object>> buildRadarSeriesForSingleUser(
            Long userId, LocalDate[] range, List<Long> indicatorIds) {

        List<DailyTaskDetail> details = getErrorDetailsByUserId(userId, range[0], range[1]);
        String name = getUserName(userId, details);
        Map<String, Object> item = buildRadarSeriesItemWithUserId(name, userId, details, indicatorIds);
        return Collections.singletonList(item);
    }

    /**
     * 构建雷达图单条 series（deptId）
     */
    private Map<String, Object> buildRadarSeriesItem(String name, Long deptId,
                                                      List<DailyTaskDetail> details,
                                                      List<Long> indicatorIds) {
        Map<String, BaseCheckCategory> qcIdToLevel1 = buildQcIdToLevel1Map(details);
        Map<Long, Long> countMap = details.stream()
                .filter(d -> qcIdToLevel1.get(d.getDtdModuleId()) != null)
                .collect(Collectors.groupingBy(
                        d -> qcIdToLevel1.get(d.getDtdModuleId()).getId(),
                        Collectors.counting()));

        List<Long> data = indicatorIds.stream()
                .map(id -> countMap.getOrDefault(id, 0L))
                .collect(Collectors.toList());

        Map<String, Object> s = new LinkedHashMap<>();
        s.put("name", name);
        s.put("deptId", deptId);
        s.put("data", data);
        return s;
    }

    /**
     * 构建雷达图单条 series（userId）
     */
    private Map<String, Object> buildRadarSeriesItemWithUserId(String name, Long userId,
                                                                List<DailyTaskDetail> details,
                                                                List<Long> indicatorIds) {
        Map<String, BaseCheckCategory> qcIdToLevel1 = buildQcIdToLevel1Map(details);
        Map<Long, Long> countMap = details.stream()
                .filter(d -> qcIdToLevel1.get(d.getDtdModuleId()) != null)
                .collect(Collectors.groupingBy(
                        d -> qcIdToLevel1.get(d.getDtdModuleId()).getId(),
                        Collectors.counting()));

        List<Long> data = indicatorIds.stream()
                .map(id -> countMap.getOrDefault(id, 0L))
                .collect(Collectors.toList());

        Map<String, Object> s = new LinkedHashMap<>();
        s.put("name", name);
        s.put("userId", userId);
        s.put("data", data);
        return s;
    }

    private RoleInfo getRoleInfo() {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        List<String> roleKeys = loginUser.getUser().getRoles().stream()
                .map(SysRole::getRoleKey).collect(Collectors.toList());
        Long userDeptId = loginUser.getDeptId();
        Long userId = loginUser.getUserId();

        boolean isStation = userId == 1L
                || roleKeys.contains(RoleTypeEnum.admin.getCode())
                || roleKeys.contains(RoleTypeEnum.test.getCode())
                || roleKeys.contains(RoleTypeEnum.zhijianke.getCode());
        boolean isBrigade = !isStation && (roleKeys.contains(RoleTypeEnum.jingli.getCode())
                || roleKeys.contains(RoleTypeEnum.xingzheng.getCode()));
        boolean isKezhang = !isStation && !isBrigade && roleKeys.contains(RoleTypeEnum.kezhang.getCode());

        RoleInfo info = new RoleInfo();
        info.isStation = isStation;
        info.isBrigade = isBrigade;
        info.isKezhang = isKezhang;
        info.userDeptId = userDeptId;
        return info;
    }

    private static class RoleInfo {
        boolean isStation;
        boolean isBrigade;
        boolean isKezhang;
        Long userDeptId;
    }

    private List<DailyTaskDetail> getErrorDetailsByDeptIds(Set<Long> deptIds, LocalDate start, LocalDate end) {
        if (deptIds == null || deptIds.isEmpty()) return Collections.emptyList();
        LambdaQueryWrapper<DailyTask> taskWrapper = new LambdaQueryWrapper<>();
        taskWrapper.in(DailyTask::getDtDeptId, deptIds);
        taskWrapper.ge(DailyTask::getDtBusinessDate, Date.valueOf(start));
        taskWrapper.le(DailyTask::getDtBusinessDate, Date.valueOf(end));
        taskWrapper.eq(DailyTask::getDelStatus, 0);
        List<DailyTask> tasks = dailyTaskMapper.selectList(taskWrapper);
        return getErrorDetailsFromTasks(tasks);
    }

    private List<DailyTaskDetail> getErrorDetailsByDepartmentId(Long departmentId, LocalDate start, LocalDate end) {
        LambdaQueryWrapper<DailyTask> taskWrapper = new LambdaQueryWrapper<>();
        taskWrapper.eq(DailyTask::getDtDepartmentId, departmentId);
        taskWrapper.ge(DailyTask::getDtBusinessDate, Date.valueOf(start));
        taskWrapper.le(DailyTask::getDtBusinessDate, Date.valueOf(end));
        taskWrapper.eq(DailyTask::getDelStatus, 0);
        List<DailyTask> tasks = dailyTaskMapper.selectList(taskWrapper);
        return getErrorDetailsFromTasks(tasks);
    }

    private List<DailyTaskDetail> getErrorDetailsByDeptId(Long deptId, LocalDate start, LocalDate end) {
        LambdaQueryWrapper<DailyTask> taskWrapper = new LambdaQueryWrapper<>();
        taskWrapper.eq(DailyTask::getDtDeptId, deptId);
        taskWrapper.ge(DailyTask::getDtBusinessDate, Date.valueOf(start));
        taskWrapper.le(DailyTask::getDtBusinessDate, Date.valueOf(end));
        taskWrapper.eq(DailyTask::getDelStatus, 0);
        List<DailyTask> tasks = dailyTaskMapper.selectList(taskWrapper);
        return getErrorDetailsFromTasks(tasks);
    }

    private List<DailyTaskDetail> getErrorDetailsByUserId(Long userId, LocalDate start, LocalDate end) {
        LambdaQueryWrapper<DailyTask> taskWrapper = new LambdaQueryWrapper<>();
        taskWrapper.eq(DailyTask::getDtUserId, userId);
        taskWrapper.ge(DailyTask::getDtBusinessDate, Date.valueOf(start));
        taskWrapper.le(DailyTask::getDtBusinessDate, Date.valueOf(end));
        taskWrapper.eq(DailyTask::getDelStatus, 0);
        List<DailyTask> tasks = dailyTaskMapper.selectList(taskWrapper);
        return getErrorDetailsFromTasks(tasks);
    }

    /**
     * 查询上级部门（大队）下所有直接子部门（主管）的错误明细
     */
    private List<DailyTaskDetail> getErrorDetailsBySubDepts(Long parentDeptId, LocalDate start, LocalDate end) {
        List<SysDept> subDepts = sysDeptMapper.selectChildrenDeptById(parentDeptId);
        if (subDepts == null || subDepts.isEmpty()) return Collections.emptyList();
        Set<Long> managerIds = subDepts.stream()
                .filter(d -> parentDeptId.equals(d.getParentId()) && "0".equals(d.getDelFlag()))
                .map(SysDept::getDeptId)
                .collect(Collectors.toSet());
        if (managerIds.isEmpty()) return Collections.emptyList();
        LambdaQueryWrapper<DailyTask> taskWrapper = new LambdaQueryWrapper<>();
        taskWrapper.in(DailyTask::getDtDepartmentId, managerIds);
        taskWrapper.ge(DailyTask::getDtBusinessDate, Date.valueOf(start));
        taskWrapper.le(DailyTask::getDtBusinessDate, Date.valueOf(end));
        taskWrapper.eq(DailyTask::getDelStatus, 0);
        List<DailyTask> tasks = dailyTaskMapper.selectList(taskWrapper);
        return getErrorDetailsFromTasks(tasks);
    }

    private List<DailyTaskDetail> getErrorDetailsFromTasks(List<DailyTask> tasks) {
        if (tasks == null || tasks.isEmpty()) return Collections.emptyList();
        Set<String> taskIds = tasks.stream().map(DailyTask::getDtId).collect(Collectors.toSet());
        LambdaQueryWrapper<DailyTaskDetail> detailWrapper = new LambdaQueryWrapper<>();
        detailWrapper.in(DailyTaskDetail::getDtdTaskId, taskIds);
        detailWrapper.eq(DailyTaskDetail::getDtdIsCorrect, false);
        detailWrapper.eq(DailyTaskDetail::getDelStatus, 0);
        return dailyTaskDetailMapper.selectList(detailWrapper);
    }

    private Map<String, BaseCheckCategory> buildQcIdToLevel1Map(List<DailyTaskDetail> details) {
        Map<String, BaseCheckCategory> result = new HashMap<>();
        Map<String, BaseCheckCategory> qcNameToLevel1Cache = new HashMap<>();

        for (DailyTaskDetail detail : details) {
            String qcId = detail.getDtdModuleId();
            if (qcId == null || qcId.trim().isEmpty() || result.containsKey(qcId)) continue;

            LambdaQueryWrapper<QuesCat> catWrapper = new LambdaQueryWrapper<>();
            catWrapper.eq(QuesCat::getQcId, qcId);
            catWrapper.eq(QuesCat::getDelStatus, 0);
            QuesCat quesCat = quesCatService.getOne(catWrapper);

            if (quesCat == null) {
                result.put(qcId, null);
                continue;
            }

            String qcName = quesCat.getQcName();
            if (qcNameToLevel1Cache.containsKey(qcName)) {
                result.put(qcId, qcNameToLevel1Cache.get(qcName));
            } else {
                BaseCheckCategory level1 = baseCheckCategoryService.selectLevel1ByLevel2Name(qcName);
                qcNameToLevel1Cache.put(qcName, level1);
                result.put(qcId, level1);
            }
        }
        return result;
    }

    private LocalDate[] resolveDateRange(String dateRangeQueryType, Integer year, Integer quarter, Integer month) {
        LocalDate today = LocalDate.now();
        int y = (year != null) ? year : today.getYear();
        String type = (dateRangeQueryType != null) ? dateRangeQueryType : "MONTH";
        LocalDate start, end;
        switch (type) {
            case "YEAR":
                start = LocalDate.of(y, 1, 1);
                end = LocalDate.of(y, 12, 31);
                break;
            case "QUARTER":
                int q = (quarter != null) ? quarter : 1;
                start = LocalDate.of(y, (q - 1) * 3 + 1, 1);
                end = start.plusMonths(3).minusDays(1);
                break;
            case "MONTH":
            default:
                int m = (month != null) ? month : today.getMonthValue();
                start = LocalDate.of(y, m, 1);
                end = start.withDayOfMonth(start.lengthOfMonth());
                break;
        }
        return new LocalDate[]{start, end};
    }

    private String getManagerName(Long managerId) {
        try {
            SysDept dept = sysDeptMapper.selectDeptById(managerId);
            if (dept != null) return dept.getDeptName();
        } catch (Exception ignored) {
        }
        return "主管" + managerId;
    }

    private String getUserName(Long userId, List<DailyTaskDetail> details) {
        if (details.isEmpty()) return "用户" + userId;
        Set<String> taskIds = details.stream().map(DailyTaskDetail::getDtdTaskId).collect(Collectors.toSet());
        LambdaQueryWrapper<DailyTask> w = new LambdaQueryWrapper<>();
        w.in(DailyTask::getDtId, taskIds);
        w.eq(DailyTask::getDelStatus, 0);
        w.last("LIMIT 1");
        DailyTask task = dailyTaskMapper.selectOne(w);
        if (task != null && task.getDtUserName() != null) return task.getDtUserName();
        return "用户" + userId;
    }
}
