package com.xy.xyaicpzs.controller;

import com.xy.xyaicpzs.common.ErrorCode;
import com.xy.xyaicpzs.common.ResultUtils;
import com.xy.xyaicpzs.common.requset.BackBallPredictionRequest;
import com.xy.xyaicpzs.common.requset.FirstBallPredictionRequest;
import com.xy.xyaicpzs.common.requset.FollowBackBallPredictionRequest;
import com.xy.xyaicpzs.common.requset.FollowerBallPredictionRequest;
import com.xy.xyaicpzs.common.response.ApiResponse;
import com.xy.xyaicpzs.domain.entity.DltDrawRecord;
import com.xy.xyaicpzs.domain.entity.DltPredictRecord;
import com.xy.xyaicpzs.domain.entity.User;
import com.xy.xyaicpzs.domain.vo.BallCombinationAnalysisVO;
import com.xy.xyaicpzs.domain.vo.BallPersistenceAnalysisVO;
import com.xy.xyaicpzs.domain.vo.FirstBallPredictionResultVO;
import com.xy.xyaicpzs.domain.vo.FollowerBallPredictionResultVO;
import com.xy.xyaicpzs.domain.vo.BackBallPredictionResultVO;
import com.xy.xyaicpzs.domain.vo.FollowBackBallPredictionResultVO;
import com.xy.xyaicpzs.dlt.BackBallPredictor;
import com.xy.xyaicpzs.dlt.FirstBallPredictor;
import com.xy.xyaicpzs.dlt.FirstBallPredictor.FirstBallPredictionResult;
import com.xy.xyaicpzs.dlt.FollowBackBallPredictor;
import com.xy.xyaicpzs.dlt.FollowerBallPredictor;
import com.xy.xyaicpzs.service.DltCombinationAnalysisService;
import com.xy.xyaicpzs.service.DltDrawRecordService;
import com.xy.xyaicpzs.service.DltPersistenceAnalysisService;
import com.xy.xyaicpzs.service.DltPredictRecordService;
import com.xy.xyaicpzs.service.UserService;
import com.xy.xyaicpzs.util.UserAuthValidator;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.*;

import java.util.Arrays;
import java.util.Date;
import java.util.List;
import jakarta.servlet.http.HttpServletRequest;

@Slf4j
@RestController
@RequestMapping("/dlt/ball-analysis")
@Tag(name = "大乐透球号分析", description = "大乐透球号分析算法API")
public class DltBallAnalysisController {

    @Autowired
    private FirstBallPredictor firstBallPredictor;

    @Autowired
    private FollowerBallPredictor followerBallPredictor;

    @Autowired
    private BackBallPredictor backBallPredictor;
    
    @Autowired
    private FollowBackBallPredictor followBackBallPredictor;

    @Autowired
    private DltPredictRecordService dltPredictRecordService;

    @Autowired
    private DltCombinationAnalysisService dltCombinationAnalysisService;

    @Autowired
    private DltPersistenceAnalysisService dltPersistenceAnalysisService;

    @Autowired
    private UserAuthValidator userAuthValidator;

    @Autowired
    private DltDrawRecordService dltDrawRecordService;

    @Autowired
    private UserService userService;

    /**
     * 获取近期大乐透开奖信息
     * @param limit 获取条数，可选参数，默认10条
     * @return 近期大乐透开奖信息列表
     */
    @GetMapping("/recent-draws")
    @Operation(summary = "获取近期大乐透开奖信息", description = "获取最近的大乐透开奖信息，默认返回10条，按开奖期号倒序排列")
    public ApiResponse<List<DltDrawRecord>> getRecentDraws(
            @Parameter(description = "获取条数，默认10条", required = false)
            @RequestParam(required = false, defaultValue = "10") Integer limit, HttpServletRequest request) {
        User loginUser = userService.getLoginUser(request);
        if (loginUser == null){
            return ResultUtils.error(ErrorCode.NOT_LOGIN_ERROR, "您还未登录，请登录后查看");
        }
        try {
            log.info("接收到获取近期大乐透开奖信息请求：条数={}", limit);
            
            // 调用服务获取近期大乐透开奖信息
            List<DltDrawRecord> result = dltDrawRecordService.getRecentDraws(limit);
            
            log.info("获取近期大乐透开奖信息完成，返回{}条记录", result.size());
            return ResultUtils.success(result);
            
        } catch (Exception e) {
            log.error("获取近期大乐透开奖信息失败：{}", e.getMessage(), e);
            return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "获取近期大乐透开奖信息失败：" + e.getMessage());
        }
    }

    @PostMapping("/predict-first-ball")
    @Operation(summary = "前区首球预测", description = "根据输入的级别和号码，预测前区首球")
    public ApiResponse<FirstBallPredictionResultVO> predictFirstBall(@RequestBody FirstBallPredictionRequest request) {
        FirstBallPredictionResult predictionResult = firstBallPredictor.predictFirstBallWithProcess(
            request.getLevel(), request.getRedBalls(), request.getBlueBalls());
        
        FirstBallPredictionResultVO resultVO = FirstBallPredictionResultVO.builder()
            .result(predictionResult.getResult())
            .filteringProcess(predictionResult.getFilteringProcess())
            .build();
            
        return ResultUtils.success(resultVO);
    }

    @PostMapping("/predict-follower-ball")
    @Operation(summary = "前区随球预测", description = "根据输入的级别和号码，预测前区随球")
    public ApiResponse<FollowerBallPredictionResultVO> predictFollowerBall(@RequestBody FollowerBallPredictionRequest request) {
        FollowerBallPredictor.FollowerBallPredictionResult result = followerBallPredictor.predictFollowerBallWithProcess(request.getLevel(), request.getWellRegardedBalls(), request.getPreviousFrontBalls(), request.getPreviousBackBalls());
        FollowerBallPredictionResultVO vo = FollowerBallPredictionResultVO.builder()
                .result(result.getResult())
                .filteringProcess(result.getFilteringProcess())
                .build();
        return ResultUtils.success(vo);
    }

    @PostMapping("/predict-back-ball")
    @Operation(summary = "后区首球预测", description = "根据输入的级别和号码，预测后区首球")
    public ApiResponse<BackBallPredictionResultVO> predictBackBall(@RequestBody BackBallPredictionRequest request) {
        BackBallPredictor.BackBallPredictionResult result = backBallPredictor.predictBackBallWithProcess(request.getLevel(), request.getNextFrontBalls(), request.getPreviousFrontBalls(), request.getPreviousBackBalls(), request.getNextBackBalls());
        BackBallPredictionResultVO vo = BackBallPredictionResultVO.builder()
                .result(result.getResult())
                .filteringProcess(result.getFilteringProcess())
                .build();
        return ResultUtils.success(vo);
    }

    @PostMapping("/predict-follow-back-ball")
    @Operation(summary = "后区随球预测", description = "根据输入的级别和号码，预测后区随球")
    public ApiResponse<FollowBackBallPredictionResultVO> predictFollowBackBall(@RequestBody FollowBackBallPredictionRequest request) {
        FollowBackBallPredictor.FollowBackBallPredictionResult result = followBackBallPredictor.predictFollowBackBallWithProcess(request.getLevel(), request.getBackFirstBall(), request.getNextFrontBalls(), request.getPreviousFrontBalls(), request.getPreviousBackBalls());
        FollowBackBallPredictionResultVO vo = FollowBackBallPredictionResultVO.builder()
                .result(result.getResult())
                .filteringProcess(result.getFilteringProcess())
                .build();
        return ResultUtils.success(vo);
    }

    /**
     * 创建大乐透预测记录
     * @param userId 用户ID
     * @param drawId 开奖期号
     * @param drawDate 开奖日期
     * @param frontBalls 5个前区球号码，用逗号分隔
     * @param backBalls 2个后区球号码，用逗号分隔
     * @return 创建的预测记录
     */
    @PostMapping("/create-dlt-predict")
    @Operation(summary = "创建大乐透预测记录", description = "向dlt_predict_record表插入一条大乐透预测记录数据")
    public ApiResponse<DltPredictRecord> createDltPredictRecord(
            @Parameter(description = "用户ID，例如：1001", required = true)
            @RequestParam Long userId,
            
            @Parameter(description = "开奖期号，例如：25001", required = true)
            @RequestParam Long drawId,
            
            @Parameter(description = "开奖日期，格式：yyyy-MM-dd", required = false)
            @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date drawDate,
            
            @Parameter(description = "5个前区球号码，用逗号分隔，例如：1,5,12,18,25", required = true)
            @RequestParam String frontBalls,
            
            @Parameter(description = "2个后区球号码，用逗号分隔，例如：8,12", required = true)
            @RequestParam String backBalls) {
        
        try {
            log.info("接收到创建大乐透预测记录请求：用户ID={}，期号={}，开奖日期={}，前区球={}，后区球={}", 
                    userId, drawId, drawDate, frontBalls, backBalls);
            
            // 解析前区球号码
            List<Integer> frontBallList = parseDltBalls(frontBalls, 5, "前区球", 1, 35);
            
            // 解析后区球号码
            List<Integer> backBallList = parseDltBalls(backBalls, 2, "后区球", 1, 12);
            
            // 调用服务创建大乐透预测记录
            DltPredictRecord result = dltPredictRecordService.createDltPredictRecord(userId, drawId, drawDate, frontBallList, backBallList);
            
            log.info("创建大乐透预测记录完成，用户ID：{}，记录ID：{}", userId, result.getId());
            return ResultUtils.success(result);
            
        } catch (Exception e) {
            log.error("创建大乐透预测记录失败：{}", e.getMessage(), e);
            return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "创建大乐透预测记录失败：" + e.getMessage());
        }
    }

    /**
     * 解析大乐透球号码字符串
     */
    private List<Integer> parseDltBalls(String balls, int expectedCount, String ballType, int minValue, int maxValue) {
        if (balls == null || balls.trim().isEmpty()) {
            throw new IllegalArgumentException(ballType + "号码不能为空");
        }
        
        try {
            String[] parts = balls.split(",");
            if (parts.length != expectedCount) {
                throw new IllegalArgumentException(ballType + "数量必须为" + expectedCount + "个，实际：" + parts.length);
            }
            
            List<Integer> result = Arrays.stream(parts)
                    .map(String::trim)
                    .map(Integer::parseInt)
                    .collect(java.util.stream.Collectors.toList());
            
            // 验证球号码范围
            for (Integer ball : result) {
                if (ball < minValue || ball > maxValue) {
                    throw new IllegalArgumentException(ballType + "号码必须在" + minValue + "-" + maxValue + "范围内，错误值：" + ball);
                }
            }
            
            return result;
            
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException(ballType + "号码格式错误，请使用逗号分隔的数字");
        }
    }

    /**
     * 前区与前区的组合性分析
     * @param masterBall 主球号码（前区）
     * @param slaveBall 随球号码（前区）
     * @return 系数分析结果
     */
    @GetMapping("/front-front-combination-analysis")
    @Operation(summary = "前区与前区的组合性分析", description = "根据前区主球和前区随球号码，查询D5表获取系数，并计算主球与其他球号的组合情况")
    public ApiResponse<BallCombinationAnalysisVO> frontFrontCombinationAnalysis(
            @Parameter(description = "主球号码（前区），例如：5", required = true)
            @RequestParam Integer masterBall,
            
            @Parameter(description = "随球号码（前区），例如：12", required = true)
            @RequestParam Integer slaveBall,
            
            HttpServletRequest request) {
        
        // 权限验证
        ApiResponse<BallCombinationAnalysisVO> authResult = userAuthValidator.validateUserAuth(request);
        if (authResult != null) {
            return authResult;
        }
        
        try {
            log.info("接收到前区与前区的组合性分析请求：主球（前区）={}，随球（前区）={}", masterBall, slaveBall);
            
            BallCombinationAnalysisVO result = dltCombinationAnalysisService.analyzeFrontFrontCombination(masterBall, slaveBall);
            
            log.info("前区与前区的组合性分析完成：{}", result);
            return ResultUtils.success(result);
            
        } catch (Exception e) {
            log.error("前区与前区的组合性分析失败：{}", e.getMessage(), e);
            return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "前区与前区的组合性分析失败：" + e.getMessage());
        }
    }

    /**
     * 前区与后区的组合性分析
     * @param masterBall 主球号码（前区）
     * @param slaveBall 随球号码（后区）
     * @return 系数分析结果
     */
    @GetMapping("/front-back-combination-analysis")
    @Operation(summary = "前区与后区的组合性分析", description = "根据前区主球和后区随球号码，查询D6表获取系数，并返回扩展分析")
    public ApiResponse<BallCombinationAnalysisVO> frontBackCombinationAnalysis(
            @Parameter(description = "主球号码（前区），例如：5", required = true)
            @RequestParam Integer masterBall,
            
            @Parameter(description = "随球号码（后区），例如：8", required = true)
            @RequestParam Integer slaveBall,
            
            HttpServletRequest request) {
        
        // 权限验证
        ApiResponse<BallCombinationAnalysisVO> authResult = userAuthValidator.validateUserAuth(request);
        if (authResult != null) {
            return authResult;
        }
        
        try {
            log.info("接收到前区与后区的组合性分析请求：主球（前区）={}，随球（后区）={}", masterBall, slaveBall);
            
            BallCombinationAnalysisVO result = dltCombinationAnalysisService.analyzeFrontBackCombination(masterBall, slaveBall);
            
            log.info("前区与后区的组合性分析完成：{}", result);
            return ResultUtils.success(result);
            
        } catch (Exception e) {
            log.error("前区与后区的组合性分析失败：{}", e.getMessage(), e);
            return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "前区与后区的组合性分析失败：" + e.getMessage());
        }
    }

    /**
     * 后区与后区的组合性分析
     * @param masterBall 主球号码（后区）
     * @param slaveBall 随球号码（后区）
     * @return 系数分析结果
     */
    @GetMapping("/back-back-combination-analysis")
    @Operation(summary = "后区与后区的组合性分析", description = "根据后区主球和后区随球号码，查询D7表获取系数，并返回扩展分析")
    public ApiResponse<BallCombinationAnalysisVO> backBackCombinationAnalysis(
            @Parameter(description = "主球号码（后区），例如：8", required = true)
            @RequestParam Integer masterBall,
            
            @Parameter(description = "随球号码（后区），例如：12", required = true)
            @RequestParam Integer slaveBall,
            
            HttpServletRequest request) {
        
        // 权限验证
        ApiResponse<BallCombinationAnalysisVO> authResult = userAuthValidator.validateUserAuth(request);
        if (authResult != null) {
            return authResult;
        }
        
        try {
            log.info("接收到后区与后区的组合性分析请求：主球（后区）={}，随球（后区）={}", masterBall, slaveBall);
            
            BallCombinationAnalysisVO result = dltCombinationAnalysisService.analyzeBackBackCombination(masterBall, slaveBall);
            
            log.info("后区与后区的组合性分析完成：{}", result);
            return ResultUtils.success(result);
            
        } catch (Exception e) {
            log.error("后区与后区的组合性分析失败：{}", e.getMessage(), e);
            return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "后区与后区的组合性分析失败：" + e.getMessage());
        }
    }

    /**
     * 后区与前区的组合性分析
     * @param masterBall 主球号码（后区）
     * @param slaveBall 随球号码（前区）
     * @return 系数分析结果
     */
    @GetMapping("/back-front-combination-analysis")
    @Operation(summary = "后区与前区的组合性分析", description = "根据后区主球和前区随球号码，查询D8表获取系数，并返回扩展分析")
    public ApiResponse<BallCombinationAnalysisVO> backFrontCombinationAnalysis(
            @Parameter(description = "主球号码（后区），例如：8", required = true)
            @RequestParam Integer masterBall,
            
            @Parameter(description = "随球号码（前区），例如：5", required = true)
            @RequestParam Integer slaveBall,
            
            HttpServletRequest request) {
        
        // 权限验证
        ApiResponse<BallCombinationAnalysisVO> authResult = userAuthValidator.validateUserAuth(request);
        if (authResult != null) {
            return authResult;
        }
        
        try {
            log.info("接收到后区与前区的组合性分析请求：主球（后区）={}，随球（前区）={}", masterBall, slaveBall);
            
            BallCombinationAnalysisVO result = dltCombinationAnalysisService.analyzeBackFrontCombination(masterBall, slaveBall);
            
            log.info("后区与前区的组合性分析完成：{}", result);
            return ResultUtils.success(result);
            
        } catch (Exception e) {
            log.error("后区与前区的组合性分析失败：{}", e.getMessage(), e);
            return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "后区与前区的组合性分析失败：" + e.getMessage());
        }
    }

    /**
     * 前区与前区的持续性分析
     * @param masterBall 主球号码（前区）
     * @param slaveBall 随球号码（前区）
     * @return 线系数分析结果
     */
    @GetMapping("/front-front-persistence-analysis")
    @Operation(summary = "前区与前区的持续性分析", description = "根据前区主球和前区随球号码，查询D9表获取线系数，并返回扩展分析")
    public ApiResponse<BallPersistenceAnalysisVO> frontFrontPersistenceAnalysis(
            @Parameter(description = "主球号码（前区），例如：5", required = true)
            @RequestParam Integer masterBall,
            
            @Parameter(description = "随球号码（前区），例如：12", required = true)
            @RequestParam Integer slaveBall,
            
            HttpServletRequest request) {
        
        // 权限验证
        ApiResponse<BallPersistenceAnalysisVO> authResult = userAuthValidator.validateUserAuth(request);
        if (authResult != null) {
            return authResult;
        }
        
        try {
            log.info("接收到前区与前区的持续性分析请求：主球（前区）={}，随球（前区）={}", masterBall, slaveBall);
            
            BallPersistenceAnalysisVO result = dltPersistenceAnalysisService.analyzeFrontFrontPersistence(masterBall, slaveBall);
            
            log.info("前区与前区的持续性分析完成：{}", result);
            return ResultUtils.success(result);
            
        } catch (Exception e) {
            log.error("前区与前区的持续性分析失败：{}", e.getMessage(), e);
            return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "前区与前区的持续性分析失败：" + e.getMessage());
        }
    }

    /**
     * 后区与后区的持续性分析
     * @param masterBall 主球号码（后区）
     * @param slaveBall 随球号码（后区）
     * @return 线系数分析结果
     */
    @GetMapping("/back-back-persistence-analysis")
    @Operation(summary = "后区与后区的持续性分析", description = "根据后区主球和后区随球号码，查询D11表获取线系数，并返回扩展分析")
    public ApiResponse<BallPersistenceAnalysisVO> backBackPersistenceAnalysis(
            @Parameter(description = "主球号码（后区），例如：8", required = true)
            @RequestParam Integer masterBall,
            
            @Parameter(description = "随球号码（后区），例如：12", required = true)
            @RequestParam Integer slaveBall,
            
            HttpServletRequest request) {
        
        // 权限验证
        ApiResponse<BallPersistenceAnalysisVO> authResult = userAuthValidator.validateUserAuth(request);
        if (authResult != null) {
            return authResult;
        }
        
        try {
            log.info("接收到后区与后区的持续性分析请求：主球（后区）={}，随球（后区）={}", masterBall, slaveBall);
            
            BallPersistenceAnalysisVO result = dltPersistenceAnalysisService.analyzeBackBackPersistence(masterBall, slaveBall);
            
            log.info("后区与后区的持续性分析完成：{}", result);
            return ResultUtils.success(result);
            
        } catch (Exception e) {
            log.error("后区与后区的持续性分析失败：{}", e.getMessage(), e);
            return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "后区与后区的持续性分析失败：" + e.getMessage());
        }
    }

    /**
     * 前区与后区的持续性分析
     * @param masterBall 主球号码（前区）
     * @param slaveBall 随球号码（后区）
     * @return 线系数分析结果
     */
    @GetMapping("/front-back-persistence-analysis")
    @Operation(summary = "前区与后区的持续性分析", description = "根据前区主球和后区随球号码，查询D10表获取线系数，并返回扩展分析")
    public ApiResponse<BallPersistenceAnalysisVO> frontBackPersistenceAnalysis(
            @Parameter(description = "主球号码（前区），例如：5", required = true)
            @RequestParam Integer masterBall,
            
            @Parameter(description = "随球号码（后区），例如：8", required = true)
            @RequestParam Integer slaveBall,
            
            HttpServletRequest request) {
        
        // 权限验证
        ApiResponse<BallPersistenceAnalysisVO> authResult = userAuthValidator.validateUserAuth(request);
        if (authResult != null) {
            return authResult;
        }
        
        try {
            log.info("接收到前区与后区的持续性分析请求：主球（前区）={}，随球（后区）={}", masterBall, slaveBall);
            
            BallPersistenceAnalysisVO result = dltPersistenceAnalysisService.analyzeFrontBackPersistence(masterBall, slaveBall);
            
            log.info("前区与后区的持续性分析完成：{}", result);
            return ResultUtils.success(result);
            
        } catch (Exception e) {
            log.error("前区与后区的持续性分析失败：{}", e.getMessage(), e);
            return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "前区与后区的持续性分析失败：" + e.getMessage());
        }
    }

    /**
     * 后区与前区的持续性分析
     * @param masterBall 主球号码（后区）
     * @param slaveBall 随球号码（前区）
     * @return 线系数分析结果
     */
    @GetMapping("/back-front-persistence-analysis")
    @Operation(summary = "后区与前区的持续性分析", description = "根据后区主球和前区随球号码，查询D12表获取线系数，并返回扩展分析")
    public ApiResponse<BallPersistenceAnalysisVO> backFrontPersistenceAnalysis(
            @Parameter(description = "主球号码（后区），例如：8", required = true)
            @RequestParam Integer masterBall,
            
            @Parameter(description = "随球号码（前区），例如：5", required = true)
            @RequestParam Integer slaveBall,
            
            HttpServletRequest request) {
        
        // 权限验证
        ApiResponse<BallPersistenceAnalysisVO> authResult = userAuthValidator.validateUserAuth(request);
        if (authResult != null) {
            return authResult;
        }
        
        try {
            log.info("接收到后区与前区的持续性分析请求：主球（后区）={}，随球（前区）={}", masterBall, slaveBall);
            
            BallPersistenceAnalysisVO result = dltPersistenceAnalysisService.analyzeBackFrontPersistence(masterBall, slaveBall);
            
            log.info("后区与前区的持续性分析完成：{}", result);
            return ResultUtils.success(result);
            
        } catch (Exception e) {
            log.error("后区与前区的持续性分析失败：{}", e.getMessage(), e);
            return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "后区与前区的持续性分析失败：" + e.getMessage());
        }
    }
}
