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.core.domain.SysAnalysisReportParamDto;
import com.sundot.airport.common.utils.DateRangeQueryUtils;
import com.sundot.airport.common.utils.SecurityUtils;
import com.sundot.airport.exam.adapter.DailyTaskToExamAdapter;
import com.sundot.airport.exam.common.ClientTypeConstant;
import com.sundot.airport.exam.common.HttpResult;
import com.sundot.airport.exam.common.PageData;
import com.sundot.airport.exam.domain.DailyTask;
import com.sundot.airport.exam.domain.DailyTaskDetail;
import com.sundot.airport.exam.dto.SubmitAnswerDTO;
import com.sundot.airport.exam.dto.SubmitResultDTO;
import com.sundot.airport.exam.logic.eighteen.model.params.ExamRecAddParam;
import com.sundot.airport.exam.logic.eighteen.model.params.Get18ExamIntroParams;
import com.sundot.airport.exam.logic.eighteen.model.params.SubmitExamParam;
import com.sundot.airport.exam.logic.eighteen.model.result.ExamGetResult;
import com.sundot.airport.exam.logic.eighteen.model.result.Get18ExamIntroResult;
import com.sundot.airport.exam.logic.eighteen.model.result.SubmitExamResult;
import com.sundot.airport.exam.logic.eighteen.model.result.subresult.ItemIn18ExamRecordListResult;
import com.sundot.airport.exam.mapper.DailyTaskDetailMapper;
import com.sundot.airport.exam.mapper.DailyTaskMapper;
import com.sundot.airport.exam.service.IDailyAnswerService;
import com.sundot.airport.system.mapper.SysDeptMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.sql.Date;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <b>功能名：</b>DailyExamController<br>
 * <b>说明：</b> 每日抽问抽答接口控制层（兼容十八大考试格式） <br>
 * <b>著作权：</b> Copyright (C) 2025 SUNDOT CORPORATION<br>
 * <b>修改履历：</b><br>
 *
 * @author 2025-01-16
 */
@RestController
@RequestMapping("/v1/cs/app/daily-exam")
public class DailyExamController {

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

    @Autowired
    private DailyTaskMapper dailyTaskMapper;

    @Autowired
    private DailyTaskDetailMapper dailyTaskDetailMapper;

    @Autowired
    private IDailyAnswerService dailyAnswerService;

    @Autowired
    private DailyTaskToExamAdapter dailyTaskAdapter;

    @Autowired
    private SysDeptMapper sysDeptMapper;

    /**
     * <b>方法名: </b> getExamIntro <br>
     * <b>说明: </b> 查询考试基本信息（兼容接口，实际返回当日任务信息） <br>
     *
     * @param param Get18ExamIntroParams 查询考试基本信息参数类
     * @return HttpResult<Get18ExamIntroResult>
     * <b>修改履历: </b>
     * @author 2025-01-16
     */
    @PostMapping("/get_exam_intro")
    public HttpResult<Get18ExamIntroResult> getExamIntro(@Validated @RequestBody Get18ExamIntroParams param) {
        log.info("获取每日任务基本信息: userId={}", SecurityUtils.getUserId());

        // 构造返回结果（固定信息）
        Get18ExamIntroResult result = new Get18ExamIntroResult();
        result.setExId("DAILY_TASK");
        result.setExName("每日抽问抽答");
        result.setExDetailImg("");
        result.setExBgImg("");

        return HttpResult.success(result);
    }

    /**
     * <b>方法名: </b> applyExam <br>
     * <b>说明: </b> 开始答题（获取今日待完成任务） <br>
     *
     * @param token java.lang.String token信息
     * @param param com.sundot.airport.exam.logic.eighteen.model.params.ExamRecAddParam 获取考试信息和试题请求参数
     * @return com.sundot.airport.exam.common.HttpResult<com.sundot.airport.exam.logic.eighteen.model.result.ExamGetResult><br>
     * <b>修改履历: </b>
     * @author 2025-01-16
     */
    @PostMapping("/get_exam")
    public HttpResult<ExamGetResult> applyExam(
            @RequestHeader(value = "Authorization", required = true) String token,
            @Validated @RequestBody ExamRecAddParam param) {

        Long userId = SecurityUtils.getUserId();
        log.info("用户申请每日答题: userId={}, param={}", userId, param);

        try {
            // 1. 查询今日待完成任务
            LambdaQueryWrapper<DailyTask> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(DailyTask::getDtUserId, userId);
            wrapper.eq(DailyTask::getDtStatus, "PENDING");
            wrapper.eq(DailyTask::getDelStatus, 0);
            wrapper.orderByAsc(DailyTask::getCreateTime);
            wrapper.last("LIMIT 1");

            DailyTask task = dailyTaskMapper.selectOne(wrapper);

            if (task == null) {
                log.warn("用户今日无待完成任务: userId={}", userId);
                return HttpResult.error("今日暂无答题任务");
            }

            // 2. 更新任务状态为答题中
            task.setDtStatus("IN_PROGRESS");
            task.setDtStartTime(new java.util.Date());
            dailyTaskMapper.updateById(task);

            // 3. 查询任务明细（题目列表）
            LambdaQueryWrapper<DailyTaskDetail> detailWrapper = new LambdaQueryWrapper<>();
            detailWrapper.eq(DailyTaskDetail::getDtdTaskId, task.getDtId());
            detailWrapper.eq(DailyTaskDetail::getDelStatus, 0);
            detailWrapper.orderByAsc(DailyTaskDetail::getDtdQuestionNo);
            List<DailyTaskDetail> details = dailyTaskDetailMapper.selectList(detailWrapper);

            // 4. 转换为考试格式返回
            ExamGetResult result = dailyTaskAdapter.convertDailyTaskToExam(task, details);

            log.info("每日答题获取成功: userId={}, taskId={}, questionCount={}",
                    userId, task.getDtId(), details.size());

            return HttpResult.success(result);

        } catch (Exception e) {
            log.error("获取每日答题失败: userId={}", userId, e);
            return HttpResult.error("获取每日答题失败：" + e.getMessage());
        }
    }

    /**
     * <b>方法名: </b> getExamRecordList <br>
     * <b>说明: </b> 查询测试记录列表（用户历史任务列表） <br>
     *
     * @return HttpResult<PageData < ItemIn18ExamRecordListResult>>
     * <b>修改履历: </b>
     * @author 2025-01-16
     */
    @PostMapping("/get_exam_record_list")
    public HttpResult<PageData<ItemIn18ExamRecordListResult>> getExamRecordList() {
        Long userId = SecurityUtils.getUserId();
        log.info("查询用户任务记录列表: userId={}", userId);

        try {
            // 查询用户所有任务记录
            LambdaQueryWrapper<DailyTask> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(DailyTask::getDtUserId, userId);
            wrapper.eq(DailyTask::getDelStatus, 0);
            wrapper.orderByDesc(DailyTask::getDtBusinessDate);
            wrapper.orderByDesc(DailyTask::getCreateTime);

            List<DailyTask> tasks = dailyTaskMapper.selectList(wrapper);

            // 转换为考试记录列表格式
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            List<ItemIn18ExamRecordListResult> results = new ArrayList<>();

            for (DailyTask task : tasks) {
                ItemIn18ExamRecordListResult item = new ItemIn18ExamRecordListResult();
                item.setErId(task.getDtId());
                item.setErExId("DAILY_TASK_" + task.getDtBusinessDate());
                item.setErExName("每日抽问抽答");
                item.setErScore(task.getDtTotalScore() != null ? task.getDtTotalScore().intValue() : 0);
                item.setCreateTime(task.getCreateTime() != null ? sdf.format(task.getCreateTime()) : "");
                item.setErExEnableCert(false); // 每日任务不启用证书
                item.setGetCert(false);

                results.add(item);
            }

            PageData<ItemIn18ExamRecordListResult> pageData = new PageData<>();
            pageData.setList(results);
            pageData.setTotal(results.size());

            return HttpResult.success(pageData);

        } catch (Exception e) {
            log.error("查询任务记录列表失败: userId={}", userId, e);
            return HttpResult.error("查询记录列表失败：" + e.getMessage());
        }
    }

    /**
     * <b>方法名: </b> getExamRecord <br>
     * <b>说明: </b> 查询测试记录详情（任务详情） <br>
     *
     * @param erId 任务ID
     * @return HttpResult
     * <b>修改履历: </b>
     * @author 2025-01-16
     */
    @PostMapping("/get_exam_record")
    public HttpResult getExamRecord(@RequestParam String erId) {
        Long userId = SecurityUtils.getUserId();
        log.info("查询任务记录详情: userId={}, taskId={}", userId, erId);

        try {
            // 查询任务主记录
            LambdaQueryWrapper<DailyTask> taskWrapper = new LambdaQueryWrapper<>();
            taskWrapper.eq(DailyTask::getDtId, erId);
            taskWrapper.eq(DailyTask::getDelStatus, 0);
            DailyTask task = dailyTaskMapper.selectOne(taskWrapper);

            if (task == null) {
                return HttpResult.error("任务不存在");
            }

            // 验证权限
            if (!task.getDtUserId().equals(userId)) {
                return HttpResult.error("无权查看该任务");
            }

            // 查询任务明细
            LambdaQueryWrapper<DailyTaskDetail> detailWrapper = new LambdaQueryWrapper<>();
            detailWrapper.eq(DailyTaskDetail::getDtdTaskId, erId);
            detailWrapper.eq(DailyTaskDetail::getDelStatus, 0);
            detailWrapper.orderByAsc(DailyTaskDetail::getDtdQuestionNo);
            List<DailyTaskDetail> details = dailyTaskDetailMapper.selectList(detailWrapper);

            // 组装返回结果
            Map<String, Object> data = new HashMap<>();
            data.put("task", task);
            data.put("details", details);

            return HttpResult.success(data);

        } catch (Exception e) {
            log.error("查询任务记录详情失败: userId={}, taskId={}", userId, erId, e);
            return HttpResult.error("查询记录详情失败：" + e.getMessage());
        }
    }

    /**
     * <b>方法名: </b> submitExam <br>
     * <b>说明: </b> 提交考试答案 <br>
     *
     * @param param SubmitExamParam 提交考试参数类
     * @return HttpResult<SubmitExamResult>
     * <b>修改履历: </b>
     * @author 2025-01-16
     */
    @PostMapping("/submit_exam")
    public HttpResult<SubmitExamResult> submitExam(@Validated @RequestBody SubmitExamParam param) {
        Long userId = SecurityUtils.getUserId();
        log.info("提交每日答题: userId={}, param={}", userId, param);

        try {
            // 1. 转换参数格式
            SubmitAnswerDTO taskDto = dailyTaskAdapter.convertExamParamToTaskSubmit(param);

            // 2. 调用答题服务提交
            SubmitResultDTO taskResult = dailyAnswerService.submitAnswer(userId, taskDto);

            // 3. 转换为考试提交结果格式
            SubmitExamResult examResult = dailyTaskAdapter.convertTaskResultToExamResult(taskResult);

            log.info("每日答题提交成功: userId={}, taskId={}, score={}",
                    userId, taskResult.getTaskId(), taskResult.getTotalScore());

            return HttpResult.success(examResult);

        } catch (Exception e) {
            log.error("提交每日答题失败: userId={}, erId={}", userId, param.getErId(), e);
            return HttpResult.error("提交答题失败：" + e.getMessage());
        }
    }

    /**
     * 抽问抽答完成趋势
     * 美兰4级架构：STATION > 大队(BRIGADE) > 主管(MANAGER) > 班组(TEAMS)
     * 站长/管理员/质检科：各大队完成趋势折线
     * 大队长（经理/行政）：本大队各主管完成趋势折线
     * 主管：本主管室完成趋势（单条折线）
     * 班组长/安检员：show=false
     *
     * @param timeType  时间类型：year/month/custom，默认 month
     * @param startDate 自定义开始日期（yyyy-MM-dd），timeType=custom 时有效
     * @param endDate   自定义结束日期（yyyy-MM-dd），timeType=custom 时有效
     */
    @GetMapping("/completion-trend")
    public HttpResult<Map<String, Object>> getCompletionTrend(
            @RequestParam(required = false, defaultValue = "month") String timeType,
            @RequestParam(required = false) String startDate,
            @RequestParam(required = false) String endDate) {

        try {
            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());

            // 班组长及以下不显示此tab
            if (!isStation && !isBrigade && !isKezhang) {
                Map<String, Object> noShow = new HashMap<>();
                noShow.put("show", false);
                return HttpResult.success(noShow);
            }

            LocalDate[] range = resolveDateRange(timeType, startDate, endDate);
            LocalDate start = range[0];
            LocalDate end = range[1];
            boolean byMonth = "year".equals(timeType);
            List<String> xAxis = buildXAxis(start, end, byMonth);
            List<Map<String, Object>> series = new ArrayList<>();

            if (isStation) {
                // 站长：查该站所有子部门，按大队分组
                List<SysDept> subDepts = sysDeptMapper.selectChildrenDeptById(userDeptId);
                if (subDepts == null) subDepts = Collections.emptyList();

                // 大队（站的直接下级）
                List<SysDept> brigadeDepts = subDepts.stream()
                        .filter(d -> userDeptId.equals(d.getParentId()) && "0".equals(d.getDelFlag()))
                        .collect(Collectors.toList());

                // 构建 主管deptId -> 所属大队deptId 的映射
                Map<Long, Long> managerToBrigadeId = new HashMap<>();
                for (SysDept d : subDepts) {
                    if ("0".equals(d.getDelFlag()) && d.getParentId() != null && !userDeptId.equals(d.getParentId())) {
                        // 非直接下级，其parentId为某个大队，记录映射（主管级别）
                        managerToBrigadeId.put(d.getDeptId(), d.getParentId());
                    }
                }

                // 查全站所有任务
                Set<Long> allDeptIds = new HashSet<>();
                allDeptIds.add(userDeptId);
                subDepts.forEach(d -> allDeptIds.add(d.getDeptId()));
                List<DailyTask> allTasks = queryTasksByDeptIds(allDeptIds, start, end);

                // 按大队分组生成折线
                for (SysDept brigade : brigadeDepts) {
                    Long brigadeId = brigade.getDeptId();
                    List<DailyTask> brigadeTasks = allTasks.stream()
                            .filter(t -> {
                                Long managerId = t.getDtDepartmentId();
                                if (managerId == null) return false;
                                Long parentBrigadeId = managerToBrigadeId.get(managerId);
                                return brigadeId.equals(parentBrigadeId);
                            })
                            .collect(Collectors.toList());
                    Map<String, Object> item = new LinkedHashMap<>();
                    item.put("name", brigade.getDeptName());
                    item.put("deptId", brigadeId);
                    item.put("data", buildSeriesData(xAxis, brigadeTasks, byMonth));
                    series.add(item);
                }

            } else if (isBrigade) {
                // 大队长：查本大队下各主管的任务
                List<SysDept> subDepts = sysDeptMapper.selectChildrenDeptById(userDeptId);
                if (subDepts == null) subDepts = Collections.emptyList();

                // 主管（大队的直接下级）
                List<SysDept> managerDepts = subDepts.stream()
                        .filter(d -> userDeptId.equals(d.getParentId()) && "0".equals(d.getDelFlag()))
                        .collect(Collectors.toList());

                for (SysDept manager : managerDepts) {
                    List<DailyTask> tasks = queryTasksByDepartmentId(manager.getDeptId(), start, end);
                    Map<String, Object> item = new LinkedHashMap<>();
                    item.put("name", manager.getDeptName());
                    item.put("deptId", manager.getDeptId());
                    item.put("data", buildSeriesData(xAxis, tasks, byMonth));
                    series.add(item);
                }

            } else {
                // 主管：本主管室所有任务，一条折线
                List<DailyTask> tasks = queryTasksByDepartmentId(userDeptId, start, end);
                String deptName = loginUser.getUser().getDept() != null
                        ? loginUser.getUser().getDept().getDeptName() : "本主管";
                Map<String, Object> item = new LinkedHashMap<>();
                item.put("name", deptName);
                item.put("deptId", userDeptId);
                item.put("data", buildSeriesData(xAxis, tasks, byMonth));
                series.add(item);
            }

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

        } catch (Exception e) {
            log.error("获取抽问抽答完成趋势失败", e);
            return HttpResult.error("获取完成趋势失败：" + e.getMessage());
        }
    }

    /**
     * 根据 timeType 计算起止日期
     * year: 当年全年；month: 当月；custom: 自定义范围
     */
    private LocalDate[] resolveDateRange(String timeType, String startDate, String endDate) {
        LocalDate today = LocalDate.now();
        LocalDate start;
        LocalDate end = today;
        switch (timeType == null ? "month" : timeType) {
            case "year":
                start = today.withDayOfYear(1);
                end = today.withMonth(12).withDayOfMonth(31);
                break;
            case "custom":
                start = (startDate != null) ? LocalDate.parse(startDate) : today.withDayOfMonth(1);
                end = (endDate != null) ? LocalDate.parse(endDate) : today;
                break;
            default: // month
                start = today.withDayOfMonth(1);
                break;
        }
        return new LocalDate[]{start, end};
    }

    /**
     * 生成X轴标签列表
     * byMonth=true：每月一个标签（格式 yyyy-MM）；false：每天一个标签（格式 yyyy-MM-dd）
     */
    private List<String> buildXAxis(LocalDate start, LocalDate end, boolean byMonth) {
        List<String> xAxis = new ArrayList<>();
        if (byMonth) {
            LocalDate cursor = start.withDayOfMonth(1);
            LocalDate endMonth = end.withDayOfMonth(1);
            while (!cursor.isAfter(endMonth)) {
                xAxis.add(cursor.format(DateTimeFormatter.ofPattern("yyyy-MM")));
                cursor = cursor.plusMonths(1);
            }
        } else {
            LocalDate cursor = start;
            while (!cursor.isAfter(end)) {
                xAxis.add(cursor.toString());
                cursor = cursor.plusDays(1);
            }
        }
        return xAxis;
    }

    /**
     * 构建某条折线的数据数组，与 xAxis 对齐
     */
    private List<Integer> buildSeriesData(List<String> xAxis, List<DailyTask> tasks, boolean byMonth) {
        SimpleDateFormat sdf = new SimpleDateFormat(byMonth ? "yyyy-MM" : "yyyy-MM-dd");
        Map<String, Long> countMap = tasks.stream()
                .filter(t -> "COMPLETED".equals(t.getDtStatus()) && t.getDtBusinessDate() != null)
                .collect(Collectors.groupingBy(
                        t -> sdf.format(t.getDtBusinessDate()),
                        Collectors.counting()));
        List<Integer> data = new ArrayList<>();
        for (String label : xAxis) {
            data.add(countMap.getOrDefault(label, 0L).intValue());
        }
        return data;
    }

    /**
     * 按部门ID集合查询任务（用于站长视角：通过dtDeptId匹配所有子部门）
     */
    private List<DailyTask> queryTasksByDeptIds(Set<Long> deptIds, LocalDate start, LocalDate end) {
        LambdaQueryWrapper<DailyTask> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(DailyTask::getDtDeptId, deptIds);
        wrapper.ge(DailyTask::getDtBusinessDate, Date.valueOf(start));
        wrapper.le(DailyTask::getDtBusinessDate, Date.valueOf(end));
        wrapper.eq(DailyTask::getDelStatus, 0);
        return dailyTaskMapper.selectList(wrapper);
    }

    /**
     * 按主管ID查询任务（通过dtDepartmentId匹配）
     */
    private List<DailyTask> queryTasksByDepartmentId(Long departmentId, LocalDate start, LocalDate end) {
        LambdaQueryWrapper<DailyTask> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DailyTask::getDtDepartmentId, departmentId);
        wrapper.ge(DailyTask::getDtBusinessDate, Date.valueOf(start));
        wrapper.le(DailyTask::getDtBusinessDate, Date.valueOf(end));
        wrapper.eq(DailyTask::getDelStatus, 0);
        return dailyTaskMapper.selectList(wrapper);
    }
}
