package org.dromara.main.controller;

import jakarta.servlet.http.HttpServletResponse;
import cn.dev33.satoken.annotation.SaCheckPermission;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.web.core.BaseController;
import org.dromara.demo.domain.dto.KaoshixingAnswerListRequest;
import org.dromara.demo.domain.dto.KaoshixingAutoLoginRequest;
import org.dromara.demo.domain.dto.KaoshixingExamListRequest;
import org.dromara.demo.domain.dto.KaoshixingRequest;
import org.dromara.demo.domain.dto.KaoshixingScoreListRequest;
import org.dromara.demo.domain.dto.KaoshixingUserExamListRequest;
import org.dromara.demo.service.impl.KaoshixingService;
import org.dromara.main.domain.MainAbilityConfig;
import org.dromara.main.domain.bo.MainExamEvaluationBo;
import org.dromara.main.domain.bo.MainExamEvaluationSyncBo;
import org.dromara.main.domain.vo.MainExamApplyListVo;
import org.dromara.main.domain.vo.MainExamResultVo;
import org.dromara.main.domain.vo.MainExamSyncEmployeeOptionVo;
import org.dromara.main.domain.vo.MainExamEvaluationVo;
import org.dromara.main.service.IMainExamEvaluationService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;

@Slf4j
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/main/examEvaluation")
public class MainExamEvaluationController extends BaseController {

    private final IMainExamEvaluationService examEvaluationService;
    private final KaoshixingService kaoshixingService;
    private final org.dromara.main.mapper.MainExamApplyMapper applyMapper;

    /**
     * 查询测评列表
     */
//    @SaCheckPermission("main:examEvaluation:list")
    @GetMapping("/list")
    public TableDataInfo<MainExamEvaluationVo> list(MainExamEvaluationBo bo, PageQuery pageQuery) {
        return examEvaluationService.queryPageList(bo, pageQuery);
    }

    @Log(title = "测评管理", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(MainExamEvaluationBo bo, HttpServletResponse response) {
        List<MainExamEvaluationVo> list = examEvaluationService.queryList(bo);
        ExcelUtil.exportExcel(list, "测评数据", MainExamEvaluationVo.class, response);
    }

//    @SaCheckPermission("main:examEvaluation:list")
    @GetMapping("/stats/participant")
    public R<Map<Long, Map<String, Long>>> participantStats(@RequestParam("ids") Collection<Long> ids) {
        return R.ok(examEvaluationService.getParticipantStats(ids));
    }

//    @SaCheckPermission("main:examEvaluation:list")
    @GetMapping("/sync/employeeOptions")
    public R<List<MainExamSyncEmployeeOptionVo>> syncEmployeeOptions() {
        return R.ok(examEvaluationService.getSyncEmployeeOptions());
    }

//    @SaCheckPermission("main:examEvaluation:sync")
    @Log(title = "同步至员工", businessType = BusinessType.UPDATE)
    @PostMapping("/sync/employees")
    public R<Void> syncToEmployees(@Validated @RequestBody MainExamEvaluationSyncBo bo) {
        return toAjax(examEvaluationService.syncToEmployees(bo));
    }

//    @SaCheckPermission("main:examEvaluation:list")
    @GetMapping("/applyList")
    public TableDataInfo<MainExamApplyListVo> applyList(@RequestParam("evaluationId") Long evaluationId,
                                                        @RequestParam(value = "keyword", required = false) String keyword,
                                                        PageQuery pageQuery) {
        return examEvaluationService.getApplyList(evaluationId, keyword, pageQuery);
    }

    @Log(title = "测评报名列表", businessType = BusinessType.EXPORT)
    @PostMapping("/applyList/export")
    public void exportApplyList(@RequestParam("evaluationId") Long evaluationId,
                                @RequestParam(value = "keyword", required = false) String keyword,
                                HttpServletResponse response) {
        List<MainExamApplyListVo> list = examEvaluationService.queryApplyList(evaluationId, keyword);
        ExcelUtil.exportExcel(list, "测评报名列表", MainExamApplyListVo.class, response);
    }

//    @SaCheckPermission("main:examEvaluation:edit")
    @Log(title = "移除测评报名", businessType = BusinessType.DELETE)
    @DeleteMapping("/apply/{applyId}")
    public R<Void> removeApply(@PathVariable("applyId") Long applyId) {
        return toAjax(examEvaluationService.removeApply(applyId));
    }

    /**
     * 获取测评详细信息
     */
//    @SaCheckPermission("main:examEvaluation:query")
    @GetMapping("/{id}")
    public R<MainExamEvaluationVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable Long id) {
        return R.ok(examEvaluationService.queryById(id));
    }

    /**
     * 新增测评
     */
//    @SaCheckPermission("main:examEvaluation:add")
    @Log(title = "测评管理", businessType = BusinessType.INSERT)
    @PostMapping()
    public R<Void> add(@Validated(AddGroup.class) @RequestBody MainExamEvaluationBo bo) {
        return toAjax(examEvaluationService.insertByBo(bo));
    }

    /**
     * 修改测评
     */
//    @SaCheckPermission("main:examEvaluation:edit")
    @Log(title = "测评管理", businessType = BusinessType.UPDATE)
    @PutMapping()
    public R<Void> edit(@Validated(EditGroup.class) @RequestBody MainExamEvaluationBo bo) {
        return toAjax(examEvaluationService.updateByBo(bo));
    }

    /**
     * 删除测评
     */
//    @SaCheckPermission("main:examEvaluation:remove")
    @Log(title = "测评管理", businessType = BusinessType.DELETE)
    @DeleteMapping("/{ids}")
    public R<Void> remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] ids) {
        return toAjax(examEvaluationService.deleteWithValidByIds(Arrays.asList(ids), true));
    }

    /**
     * 批量更新状态
     */
//    @SaCheckPermission("main:examEvaluation:edit")
    @Log(title = "测评管理", businessType = BusinessType.UPDATE)
    @PutMapping("/updateStatus")
    public R<Void> updateStatus(@RequestBody List<Long> ids, @RequestParam String status) {
        return toAjax(examEvaluationService.updateStatus(ids, status));
    }

    /**
     * 单个更新状态
     */
//    @SaCheckPermission("main:examEvaluation:edit")
    @Log(title = "测评管理", businessType = BusinessType.UPDATE)
    @PutMapping("/status/{id}/{status}")
    public R<Void> updateSingleStatus(@NotNull(message = "主键不能为空") @PathVariable Long id,
                                      @PathVariable String status) {
        return toAjax(examEvaluationService.updateStatus(id, status));
    }

    /**
     * 同步第三方数据
     */
//    @SaCheckPermission("main:examEvaluation:sync")
    @Log(title = "测评管理", businessType = BusinessType.OTHER)
    @PostMapping("/sync")
    public R<Void> syncThirdPartyData() {
        return toAjax(examEvaluationService.syncThirdPartyData());
    }



//    @SaCheckPermission("main:evaluation:list")
    @ResponseBody
    @PostMapping("/exam-list")
    @Log(title = "获取第三方考试列表", businessType = BusinessType.OTHER)
    public R<String> getExamList(@RequestBody Map<String, Object> params) {
        // 写死的第三方凭证
        String appId = "631088";  // TODO: 后续改为配置
        String appKey = "605f5f51895f423195850957bb903a43"; // TODO: 后续改为配置

        // 构建请求参数
        KaoshixingExamListRequest request = new KaoshixingExamListRequest();
        request.setAppId(appId);
        request.setAppKey(appKey);
        request.setPage((Integer) params.getOrDefault("page", 1));

        // 转换日期格式：2026-01-01 -> 2026-01-01 00:00:00
        String examStartTime = (String) params.get("examStartTime");
        if (examStartTime != null && !examStartTime.isEmpty()) {
            request.setExamStartTime(examStartTime + " 00:00:00");
        }

        String examEndTime = (String) params.get("examEndTime");
        if (examEndTime != null && !examEndTime.isEmpty()) {
            request.setExamEndTime(examEndTime + " 23:59:59");
        }

        request.setExamIds((String) params.get("examIds"));
        request.setExpSeconds((Integer) params.getOrDefault("expSeconds", 300));

        // 调用第三方接口
        String result = kaoshixingService.fetchExamList(request);
        return R.ok(result);
    }


//    @SaCheckPermission("main:evaluation:list")
    @PostMapping("/score-list")
    @Log(title = "获取考生分数列表", businessType = BusinessType.OTHER)
    public R<String> getScoreList(@RequestBody Map<String, Object> params) {
        KaoshixingScoreListRequest request = new KaoshixingScoreListRequest();
        Object examInfoIdObj = params.get("examInfoId");
        if (examInfoIdObj == null) {
            return R.fail("examInfoId不能为空");
        }
        request.setExamInfoId(Long.valueOf(examInfoIdObj.toString()));
        request.setPage((Integer) params.getOrDefault("page", 1));
        return R.ok(kaoshixingService.fetchScoreList(request));
    }

    /**
     * 获取试卷试题列表 (603)
     */
//    @SaCheckPermission("main:evaluation:list")
    @PostMapping("/paper-questions")
    public R<String> getPaperQuestions(@RequestBody Map<String, Object> params) {
        KaoshixingRequest request = new KaoshixingRequest();
        request.setExamInfoId(Long.valueOf(params.get("examInfoId").toString()));
        return R.ok(kaoshixingService.fetchExamPaperQuestions(request));
    }

    /**
     * 获取考生答案列表 (604)
     */
//    @SaCheckPermission("main:evaluation:list")
    @PostMapping("/answer-list")
    public R<String> getAnswerList(@RequestBody Map<String, Object> params) {
        KaoshixingAnswerListRequest request = new KaoshixingAnswerListRequest();
        request.setExamInfoId(Long.valueOf(params.get("examInfoId").toString()));
        return R.ok(kaoshixingService.fetchAnswerList(request));
    }

    /**
     * 获取在线学习内容列表 (605)
     */
//    @SaCheckPermission("main:evaluation:list")
    @PostMapping("/learning-contents")
    public R<String> getLearningContents(@RequestBody Map<String, Object> params) {
        KaoshixingExamListRequest request = new KaoshixingExamListRequest();
        request.setPage((Integer) params.getOrDefault("page", 1));
        return R.ok(kaoshixingService.fetchLearningContents(request));
    }

    /**
     * 获取考生可见考试和考试结果整合列表 (702)
     */
//    @SaCheckPermission("main:evaluation:list")
    @PostMapping("/user-exam-list")
    public R<String> getUserExamList(@RequestBody Map<String, Object> params) {
        Object userIdObj = params.get("user_id");
        if (userIdObj == null || userIdObj.toString().isBlank()) {
            return R.fail("user_id不能为空");
        }

        KaoshixingUserExamListRequest request = new KaoshixingUserExamListRequest();
        request.setUserId(userIdObj.toString());
        request.setPage((Integer) params.getOrDefault("page", 1));
        return R.ok(kaoshixingService.fetchUserExamList(request));
    }

    /**
     * 小程序专用：考生静默登录（action_id=203）
     * 逻辑调整：支持一场测评对应多个考试链接，并从 main_ability_config 获取。
     */
    @PostMapping("/silent-login")
    @Log(title = "考试星静默登录", businessType = BusinessType.OTHER)
    public R<Map<String, Object>> silentLogin(@RequestBody Map<String, Object> params) {
        String userId = (String) params.get("user_id");
        if (userId == null || userId.isBlank()) {
            return R.fail("user_id不能为空");
        }
        String userName  = (String) params.getOrDefault("user_name",  "学员");
        String department = (String) params.getOrDefault("department", "学员");
        String customUrl  = (String) params.get("custom_url");

        // 获取测评ID
        Long evaluationId = null;
        Object evalIdObj = params.get("evaluationId");
        if (evalIdObj != null && !evalIdObj.toString().isBlank()) {
            try {
                evaluationId = Long.valueOf(evalIdObj.toString());
            } catch (Exception e) {
                log.warn("无效的测评ID: {}", evalIdObj);
            }
        }

        try {
            List<Map<String, String>> exams = new java.util.ArrayList<>();
            com.fasterxml.jackson.databind.ObjectMapper mapper = new com.fasterxml.jackson.databind.ObjectMapper();

            // 如果传了测评ID，优先从能力配置表获取链接
            if (evaluationId != null) {
                MainExamEvaluationVo evaluationVo = examEvaluationService.queryById(evaluationId);
                if (evaluationVo != null && evaluationVo.getAbilityConfigs() != null) {
                    for (org.dromara.main.domain.MainAbilityConfig config : evaluationVo.getAbilityConfigs()) {
                        if (org.dromara.common.core.utils.StringUtils.isNotBlank(config.getThirdExamLink())) {
                            // 为每个配置的考试生成带Token的链接
                            KaoshixingAutoLoginRequest req = new KaoshixingAutoLoginRequest();
                            req.setUserId(userId);
                            req.setUserName(userName);
                            req.setDepartment(department);
                            req.setCustomUrl(config.getThirdExamLink());

                            String resp = kaoshixingService.fetchAutoLogin(req);
                            com.fasterxml.jackson.databind.JsonNode root = mapper.readTree(resp);
                            if (root.path("code").asInt() == 10000) {
                                String url = root.path("url").asText(null);
                                if (url != null) {
                                    Map<String, String> examMap = new java.util.HashMap<>();
                                    examMap.put("name", config.getAbilityName()); // 考试/维度名称
                                    examMap.put("url", url); // 授权后的链接
                                    exams.add(examMap);
                                }
                            }
                        }
                    }
                }
            }

            Map<String, Object> data = new java.util.HashMap<>();
            // 如果找到了配置的考试链接
            if (!exams.isEmpty()) {
                data.put("exams", exams);
                data.put("url", exams.get(0).get("url")); // 默认提供第一个链接
                return R.ok(data);
            }

            // 兜底逻辑：如果没配置或查询失败，走原有的跳转逻辑
            KaoshixingAutoLoginRequest req = new KaoshixingAutoLoginRequest();
            req.setUserId(userId);
            req.setUserName(userName);
            req.setDepartment(department);
            req.setCustomUrl(customUrl);

            String resp = kaoshixingService.fetchAutoLogin(req);
            com.fasterxml.jackson.databind.JsonNode root = mapper.readTree(resp);
            if (root.path("code").asInt() != 10000) {
                return R.fail(root.path("msg").asText("登录失败"));
            }
            data.put("url", root.path("url").asText());
            return R.ok(data);
        } catch (Exception e) {
            log.error("考试星静默登录失败", e);
            return R.fail("登录失败：" + e.getMessage());
        }
    }


    @GetMapping("/result/{evaluationId}")
    public R<MainExamResultVo> getEvaluationResult(@PathVariable Long evaluationId, @RequestParam Long studentId) {
        // 1. 获取该测评下的所有能力配置
        MainExamEvaluationVo evaluationVo = examEvaluationService.queryById(evaluationId);
        List<MainAbilityConfig> configs = evaluationVo.getAbilityConfigs();
        if (configs == null || configs.isEmpty()) {
            return R.fail("测评未配置能力项");
        }

        // 2. 调用考试星 702 接口获取用户的所有考试结果
        KaoshixingUserExamListRequest req = new KaoshixingUserExamListRequest();
        req.setUserId(String.valueOf(studentId));
        req.setPage(1);
        String resp = kaoshixingService.fetchUserExamList(req);

        // 3. 解析第三方数据并对比
        MainExamResultVo resultVo = new MainExamResultVo();
        List<MainExamResultVo.AbilityResult> abilityResults = new java.util.ArrayList<>();
        List<String> categories = new java.util.ArrayList<>();
        List<BigDecimal> scores = new java.util.ArrayList<>();

        int finishedCount = 0;
        boolean isAllPass = true;

        try {
            com.fasterxml.jackson.databind.JsonNode root = new com.fasterxml.jackson.databind.ObjectMapper().readTree(resp);
            com.fasterxml.jackson.databind.JsonNode rows = root.path("bizContent").path("rows");

            for (MainAbilityConfig config : configs) {
                categories.add(config.getAbilityName());
                boolean found = false;

                // 在第三方记录中查找对应的考试ID
                for (com.fasterxml.jackson.databind.JsonNode row : rows) {
                    if (row.path("examInfoId").asLong() == config.getThirdExamInfoId()) {
                        String status = row.path("status").asText();
                        if ("checked".equals(status)) {
                            BigDecimal score = new BigDecimal(row.path("results").asText("0"));
                            BigDecimal passScore = config.getThirdExamPassMark();

                            MainExamResultVo.AbilityResult ar = new MainExamResultVo.AbilityResult();
                            ar.setName(config.getAbilityName());
                            ar.setScore(score);
                            ar.setPassScore(passScore);
                            ar.setIsPass(score.compareTo(passScore) >= 0);
                            ar.setInquireLink(row.path("inquireLink").asText(null));

                            abilityResults.add(ar);
                            scores.add(score);

                            if (!ar.getIsPass()) isAllPass = false;
                            finishedCount++;
                            found = true;
                            break;
                        }
                    }
                }

                if (!found) {
                    scores.add(BigDecimal.ZERO);
                }
            }

            boolean allFinished = (finishedCount == configs.size());
            String finalResult = isAllPass ? "1" : "2";

            resultVo.setAllFinished(allFinished);
            resultVo.setFinalResult(finalResult);
            resultVo.setAbilityResults(abilityResults);

            MainExamResultVo.RadarChartData radar = new MainExamResultVo.RadarChartData();
            radar.setCategories(categories);
            radar.setSeries(scores);
            resultVo.setRadarChart(radar);

            // 4. 同步更新 main_exam_apply 记录
            try {
                org.dromara.main.domain.MainExamApply apply = applyMapper.selectOne(new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<org.dromara.main.domain.MainExamApply>()
                    .eq(org.dromara.main.domain.MainExamApply::getEvaluationId, evaluationId)
                    .eq(org.dromara.main.domain.MainExamApply::getStudentId, studentId)
                    .eq(org.dromara.main.domain.MainExamApply::getDelFlag, "0")
                    .last("LIMIT 1"));

                if (apply != null) {
                    boolean changed = false;
                    // 如果全部完成，更新状态为已完成(2)
                    if (allFinished && !"2".equals(apply.getApplyStatus())) {
                        apply.setApplyStatus("2");
                        apply.setFinishedTime(new java.util.Date());
                        changed = true;
                    } else if (finishedCount > 0 && "0".equals(apply.getApplyStatus())) {
                        // 如果有答题记录但没完，更新为进行中(1)
                        apply.setApplyStatus("1");
                        changed = true;
                    }

                    // 更新通过结果
                    if (allFinished && !finalResult.equals(apply.getFinalResult())) {
                        apply.setFinalResult(finalResult);
                        changed = true;
                    }

                    if (changed) {
                        applyMapper.updateById(apply);
                        log.info("同步更新测评申请状态成功，applyId: {}, status: {}, result: {}", apply.getId(), apply.getApplyStatus(), apply.getFinalResult());
                    }
                }
            } catch (Exception e) {
                log.error("更新测评申请记录失败", e);
            }

            return R.ok(resultVo);
        } catch (Exception e) {
            log.error("解析考试结果失败", e);
            return R.fail("获取结果失败");
        }
    }

    /**
     * 获取学员在某测评下的详细考试结果（对接考试星 action_id=10000）
     * 返回每个能力维度的多次作答记录详情
     */
    @GetMapping("/detail-result/{evaluationId}")
    public R<Map<String, Object>> getDetailResult(@PathVariable Long evaluationId, @RequestParam Long studentId) {
        try {
            // 1. 获取测评信息及能力配置
            MainExamEvaluationVo evaluationVo = examEvaluationService.queryById(evaluationId);
            if (evaluationVo == null) {
                return R.fail("测评不存在");
            }
            List<MainAbilityConfig> configs = evaluationVo.getAbilityConfigs();
            if (configs == null || configs.isEmpty()) {
                return R.fail("测评未配置能力项");
            }

            String userId = String.valueOf(studentId);
            com.fasterxml.jackson.databind.ObjectMapper mapper = new com.fasterxml.jackson.databind.ObjectMapper();

            // 2. 遍历每个能力配置，调用考试星10000接口获取详细结果
            List<Map<String, Object>> abilityDetails = new java.util.ArrayList<>();

            for (MainAbilityConfig config : configs) {
                Map<String, Object> abilityMap = new java.util.HashMap<>();
                abilityMap.put("abilityName", config.getAbilityName());
                abilityMap.put("examInfoId", config.getThirdExamInfoId());
                abilityMap.put("examName", config.getThirdExamName());
                abilityMap.put("passMark", config.getThirdExamPassMark());
                abilityMap.put("totalScore", config.getThirdExamTotalScore());

                // 调用考试星10000接口获取该学员在此考试中的作答记录
                String resultJson = kaoshixingService.fetchExamResult(userId, config.getThirdExamInfoId(), 1);

                com.fasterxml.jackson.databind.JsonNode rootNode = mapper.readTree(resultJson);
                com.fasterxml.jackson.databind.JsonNode bizContent = rootNode.path("bizContent");

                List<Map<String, Object>> records = new java.util.ArrayList<>();
                com.fasterxml.jackson.databind.JsonNode rowsNode = bizContent.path("rows");
                if (rowsNode != null && rowsNode.isArray()) {
                    for (com.fasterxml.jackson.databind.JsonNode row : rowsNode) {
                        Map<String, Object> record = new java.util.HashMap<>();
                        record.put("userId", row.path("userId").asText(""));
                        record.put("examId", row.path("examId").asInt(0));
                        record.put("examName", row.path("examName").asText(""));
                        record.put("examStartTime", row.path("examStartTime").asText(""));
                        record.put("examEndTime", row.path("examEndTime").asText(""));
                        record.put("examTime", row.path("examTime").asInt(0)); // 分钟
                        record.put("startTime", row.path("startTime").asText(""));
                        record.put("commitTime", row.path("commitTime").asText(null));
                        record.put("score", row.path("score").asText("0"));
                        record.put("isPass", row.path("isPass").asInt(-1)); // 1=及格, 0=不及格
                        record.put("times", row.path("times").asInt(0)); // 作答次数
                        record.put("examResultsId", row.path("examResultsId").asInt(0));
                        record.put("examStyleName", row.path("examStyleName").asText(""));
                        records.add(record);
                    }
                }

                abilityMap.put("records", records);
                abilityMap.put("total", bizContent.path("total").asInt(0));
                abilityDetails.add(abilityMap);
            }

            Map<String, Object> resultMap = new java.util.HashMap<>();
            resultMap.put("evaluationName", evaluationVo.getEvaluationName());
            resultMap.put("abilityDetails", abilityDetails);

            return R.ok(resultMap);
        } catch (Exception e) {
            log.error("获取考试详情结果失败", e);
            return R.fail("获取详情失败：" + e.getMessage());
        }
    }
}

