package org.dromara.demo.service.impl;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.dromara.demo.domain.dto.*;
import org.springframework.stereotype.Service;

import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
 * 考试星-试卷试题列表接口（action_id=603，完全对齐文档）
 */
@Slf4j
@Service
public class KaoshixingService {

    // 文档指定的基础接口地址
    private static final String BASE_API_URL = "https://api.kaoshixing.com/api/company/data/";
    // 试卷试题列表固定action_id
    private static final String ACTION_ID_QUESTIONS = "603";
    // 考试列表 action_id
    private static final String ACTION_ID_EXAMS = "601";
    // 考生分数列表 action_id
    private static final String ACTION_ID_SCORES = "602";
    // 考生答案列表 action_id
    private static final String ACTION_ID_ANSWERS = "604";
    // 考生可见考试+结果列表 action_id
    private static final String ACTION_ID_USER_EXAMS = "702";
    // 静默登录 action_id
    private static final String ACTION_ID_SILENT_LOGIN = "203";
    // 在线学习内容列表 action_id
    private static final String ACTION_ID_LEARNING_CONTENTS = "605";
    // 考生登录（可注册） action_id
    private static final String ACTION_ID_LOGIN = "201";
    // 查询考生信息 action_id
    private static final String ACTION_ID_QUERY_USER = "209";
    // JWT过期时间（30秒，考虑网络延迟）
    private static final long EXPIRATION_SECONDS = 30L;

    // 固定的 appId / appKey（按需求写死）
    private static final String FIXED_APP_ID = "631088";
    private static final String FIXED_APP_KEY = "605f5f51895f423195850957bb903a43";

    private final ObjectMapper objectMapper = new ObjectMapper();
    /**
     * 调用试卷试题列表接口
     * examInfoId 考试ID（示例：119551）
     * @return 试题列表JSON字符串
     */
    public String fetchExamPaperQuestions(KaoshixingRequest request) {
        Long examInfoId = request.getExamInfoId();

        validateParams(FIXED_APP_ID, FIXED_APP_KEY, examInfoId);

        String jwtInfo = generateJwt(FIXED_APP_KEY, ACTION_ID_QUESTIONS);
        log.info("试卷试题列表接口JWT：{}", jwtInfo);

        String requestUrl = String.format("%s%s/?jwt=%s", BASE_API_URL, FIXED_APP_ID, jwtInfo);
        log.info("试卷试题列表接口请求地址：{}", requestUrl);

        String requestBody = String.format("{\"examInfoId\":\"%s\"}", examInfoId);
        log.info("试卷试题列表接口请求体：{}", requestBody);

        return sendPostRequest(requestUrl, requestBody);
    }

    /**
     * 考生答案列表（action_id=604）
     */
    public String fetchAnswerList(KaoshixingAnswerListRequest req) {
        validateAnswerListParams(req);

        String jwtInfo = generateJwt(FIXED_APP_KEY, ACTION_ID_ANSWERS);
        log.info("考生答案列表接口JWT：{}", jwtInfo);

        String requestUrl = String.format("%s%s/?jwt=%s", BASE_API_URL, FIXED_APP_ID, jwtInfo);
        log.info("考生答案列表接口请求地址：{}", requestUrl);

        String requestBody = buildAnswerListBody(req);
        log.info("考生答案列表接口请求体：{}", requestBody);

        return sendPostRequest(requestUrl, requestBody);
    }

    /**
     * 考生分数列表（action_id=602）
     */
    public String fetchScoreList(KaoshixingScoreListRequest req) {
        validateScoreListParams(req);

        String jwtInfo = generateJwt(FIXED_APP_KEY, ACTION_ID_SCORES);
        log.info("考生分数列表接口JWT：{}", jwtInfo);

        String requestUrl = String.format("%s%s/?jwt=%s", BASE_API_URL, FIXED_APP_ID, jwtInfo);
        log.info("考生分数列表接口请求地址：{}", requestUrl);

        String requestBody = buildScoreListBody(req);
        log.info("考生分数列表接口请求体：{}", requestBody);

        return sendPostRequest(requestUrl, requestBody);
    }

    /**
     * 免注册登录：始终使用考生登录(201)
     */
    public String fetchAutoLogin(KaoshixingAutoLoginRequest req) {
        // 始终走 201：由考试星侧完成已存在用户登录或首次注册后登录
        String loginJwt = generateJwt(FIXED_APP_KEY, ACTION_ID_LOGIN);
        String loginUrl = String.format("%s%s/?jwt=%s", BASE_API_URL, FIXED_APP_ID, loginJwt);
        String loginBody = buildLoginBody(req);
        log.info("考生登录(201)请求体：{}", loginBody);
        return sendPostRequest(loginUrl, loginBody);
    }

    /**
     * 获取考生可见考试和考试结果整合列表（action_id=702）
     */
    public String fetchUserExamList(KaoshixingUserExamListRequest req) {
        validateUserExamListParams(req);

        String jwtInfo = generateJwt(FIXED_APP_KEY, ACTION_ID_USER_EXAMS);
        log.info("考生可见考试列表接口JWT：{}", jwtInfo);

        String requestUrl = String.format("%s%s/?jwt=%s", BASE_API_URL, FIXED_APP_ID, jwtInfo);
        log.info("考生可见考试列表接口请求地址：{}", requestUrl);

        String requestBody = String.format("{\"user_id\":\"%s\",\"page\":%d}", req.getUserId(), req.getPage());
        log.info("考生可见考试列表接口请求体：{}", requestBody);

        return sendPostRequest(requestUrl, requestBody);
    }

    /**
     * 调用考试信息列表接口（action_id=601，支持分页及时间筛选）
     */
    public String fetchExamList(KaoshixingExamListRequest req) {
        validateExamListParams(req);

        // 使用请求中的过期时间，如果没有则使用默认值
        Integer expSeconds = req.getExpSeconds() != null ? req.getExpSeconds() : 300;
        String jwtInfo = generateJwt(FIXED_APP_KEY, ACTION_ID_EXAMS, expSeconds);
        log.info("考试信息列表接口JWT：{}", jwtInfo);

        String requestUrl = String.format("%s%s/?jwt=%s", BASE_API_URL, FIXED_APP_ID, jwtInfo);
        log.info("考试信息列表接口请求地址：{}", requestUrl);

        String requestBody = buildExamListBody(req);
        log.info("考试信息列表接口请求体：{}", requestBody);

        return sendPostRequest(requestUrl, requestBody);
    }

    /**
     * 在线学习内容列表（action_id=605）
     */
    public String fetchLearningContents(KaoshixingExamListRequest req) {
        validateExamListParams(req);

        String jwtInfo = generateJwt(FIXED_APP_KEY, ACTION_ID_LEARNING_CONTENTS);
        log.info("在线学习内容列表接口JWT：{}", jwtInfo);

        String requestUrl = String.format("%s%s/?jwt=%s", BASE_API_URL, FIXED_APP_ID, jwtInfo);
        log.info("在线学习内容列表接口请求地址：{}", requestUrl);

        // 分页获取学习内容
        String requestBody = String.format("{\"page\":%d}", req.getPage());
        log.info("在线学习内容列表接口请求体：{}", requestBody);

        return sendPostRequest(requestUrl, requestBody);
    }


    /**
     * 生成JWT（使用默认过期时间）
     */
    private String generateJwt(String appKey, String actionId) {
        return generateJwt(appKey, actionId, EXPIRATION_SECONDS);
    }

    /**
     * 生成JWT（自定义过期时间）
     */
    private String generateJwt(String appKey, String actionId, long expirationSeconds) {
        // 按照考试星官方文档要求：使用毫秒级时间戳
        long currentTimeMillis = System.currentTimeMillis();
        long expTimeMillis = currentTimeMillis + expirationSeconds * 1000;

        log.info("JWT生成参数 - appKey: {}, actionId: {}, 当前时间(毫秒): {}, 过期时间(毫秒): {}, 有效期: {}秒",
                appKey, actionId, currentTimeMillis, expTimeMillis, expirationSeconds);

        String jwt = Jwts.builder()
            .claim("exp", expTimeMillis) // 考试星要求毫秒级时间戳，不是JWT标准的秒级
            .claim("action_id", actionId)
            .signWith(
                SignatureAlgorithm.HS256,
                appKey.getBytes(StandardCharsets.UTF_8)
            )
            .compact();
        
        log.info("生成的JWT: {}", jwt);
        return jwt;
    }

    private boolean userExists(String userId) {
        try {
            String queryJwt = generateJwt(FIXED_APP_KEY, ACTION_ID_QUERY_USER);
            String queryUrl = String.format("%s%s/?jwt=%s", BASE_API_URL, FIXED_APP_ID, queryJwt);
            String queryBody = String.format("{\"user_id\":\"%s\"}", userId);
            log.info("查询考生信息请求体：{}", queryBody);
            String resp = sendPostRequest(queryUrl, queryBody);
            JsonNode root = objectMapper.readTree(resp);
            if (root.get("code") != null && root.get("code").asInt() == 10000) {
                JsonNode rowCount = root.get("rowCount");
                JsonNode total = root.get("total");
                int count = 0;
                if (rowCount != null) {
                    count = rowCount.asInt(0);
                } else if (total != null) {
                    count = total.asInt(0);
                }
                return count > 0;
            }
        } catch (Exception e) {
            log.warn("查询考生信息失败，视为不存在", e);
        }
        return false;
    }


    /**
     * 发送POST请求（对齐官方示例的HttpClient）
     */
    private String sendPostRequest(String url, String body) {
        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            HttpPost httpPost = new HttpPost(url);
            // 文档要求的Content-Type（JSON格式）
            httpPost.addHeader("Content-Type", "application/json");
            // 设置请求体（UTF-8编码）
            httpPost.setEntity(new StringEntity(body, StandardCharsets.UTF_8.toString()));

            // 执行请求
            try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
                HttpEntity entity = response.getEntity();
                String responseContent = EntityUtils.toString(entity, StandardCharsets.UTF_8.toString());

                // 打印响应信息
                log.info("接口响应码：{}", response.getStatusLine().getStatusCode());
                log.info("接口响应体：{}", responseContent);

                // 非200响应抛出异常
                if (response.getStatusLine().getStatusCode() != 200) {
                    throw new RuntimeException(String.format(
                        "接口请求失败：状态码=%s，内容=%s",
                        response.getStatusLine().getStatusCode(),
                        responseContent
                    ));
                }
                return responseContent;
            }
        } catch (Exception e) {
            log.error("调用试卷试题列表接口失败", e);
            throw new RuntimeException("接口调用失败：" + e.getMessage());
        }
    }


    /**
     * 校验必填参数
     */
    private void validateParams(String appId, String appKey, Long examInfoId) {
        if (isBlank(appId)) {
            throw new IllegalArgumentException("appId不能为空（来自考试星后台）");
        }
        if (isBlank(appKey)) {
            throw new IllegalArgumentException("appKey不能为空（来自考试星后台）");
        }
        if (examInfoId == null) {
            throw new IllegalArgumentException("examInfoId不能为空（考试ID）");
        }
    }

    private void validateExamListParams(KaoshixingExamListRequest req) {
        if (req.getPage() == null) {
            throw new IllegalArgumentException("page不能为空");
        }
    }

    private void validateScoreListParams(KaoshixingScoreListRequest req) {
        if (req.getExamInfoId() == null) {
            throw new IllegalArgumentException("examInfoId不能为空");
        }
        if (req.getPage() == null) {
            throw new IllegalArgumentException("page不能为空");
        }
    }

    private void validateAnswerListParams(KaoshixingAnswerListRequest req) {
        if (req.getExamInfoId() == null) {
            throw new IllegalArgumentException("examInfoId不能为空");
        }
    }

    private void validateUserExamListParams(KaoshixingUserExamListRequest req) {
        if (isBlank(req.getUserId())) {
            throw new IllegalArgumentException("user_id不能为空");
        }
        if (req.getPage() == null) {
            throw new IllegalArgumentException("page不能为空");
        }
    }

    private String buildLoginBody(KaoshixingAutoLoginRequest req) {
        try {
            Map<String, Object> payload = new HashMap<>();
            payload.put("user_id", req.getUserId());
            payload.put("user_name", req.getUserName());
            payload.put("department", req.getDepartment());
            if (!isBlank(req.getCustomUrl())) {
                payload.put("custom_url", req.getCustomUrl());
            }
            return objectMapper.writeValueAsString(payload);
        } catch (Exception e) {
            log.error("构造登录请求体失败", e);
            throw new RuntimeException("构造请求体失败：" + e.getMessage());
        }
    }

    private boolean isSuccessResponse(String resp) {
        try {
            JsonNode root = objectMapper.readTree(resp);
            JsonNode codeNode = root.get("code");
            return codeNode != null && codeNode.asInt() == 10000;
        } catch (Exception e) {
            log.warn("解析响应判断成功标识失败，默认视为失败", e);
            return false;
        }
    }

    private String buildExamListBody(KaoshixingExamListRequest req) {
        try {
            Map<String, Object> payload = new HashMap<>();
            payload.put("page", req.getPage());
            if (!isBlank(req.getExamStartTime())) {
                payload.put("examStartTime", req.getExamStartTime());
            }
            if (!isBlank(req.getExamEndTime())) {
                payload.put("examEndTime", req.getExamEndTime());
            }
            if (!isBlank(req.getCreateTime())) {
                payload.put("createTime", req.getCreateTime());
            }
            if (!isBlank(req.getExamIds())) {
                payload.put("examIds", req.getExamIds());
            }
            return objectMapper.writeValueAsString(payload);
        } catch (Exception e) {
            log.error("构造考试信息列表请求体失败", e);
            throw new RuntimeException("构造请求体失败：" + e.getMessage());
        }
    }

    private String buildScoreListBody(KaoshixingScoreListRequest req) {
        try {
            Map<String, Object> payload = new HashMap<>();
            payload.put("examInfoId", req.getExamInfoId());
            payload.put("page", req.getPage());
            return objectMapper.writeValueAsString(payload);
        } catch (Exception e) {
            log.error("构造成绩列表请求体失败", e);
            throw new RuntimeException("构造请求体失败：" + e.getMessage());
        }
    }

    private String buildAnswerListBody(KaoshixingAnswerListRequest req) {
        try {
            Map<String, Object> payload = new HashMap<>();
            payload.put("examInfoId", req.getExamInfoId());
            return objectMapper.writeValueAsString(payload);
        } catch (Exception e) {
            log.error("构造答案列表请求体失败", e);
            throw new RuntimeException("构造请求体失败：" + e.getMessage());
        }
    }

    private boolean isBlank(String val) {
        return val == null || val.trim().isEmpty();
    }
}
