package com.xy.xyaicpzs.service.impl;

import com.xy.xyaicpzs.domain.entity.DltDrawRecord;
import com.xy.xyaicpzs.domain.entity.D5;
import com.xy.xyaicpzs.domain.entity.D6;
import com.xy.xyaicpzs.domain.entity.D7;
import com.xy.xyaicpzs.domain.entity.D8;
import com.xy.xyaicpzs.domain.vo.BallCombinationAnalysisVO;
import com.xy.xyaicpzs.service.DltCombinationAnalysisService;
import com.xy.xyaicpzs.service.DltDrawRecordService;
import com.xy.xyaicpzs.service.D5Service;
import com.xy.xyaicpzs.service.D6Service;
import com.xy.xyaicpzs.service.D7Service;
import com.xy.xyaicpzs.service.D8Service;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Comparator;
import java.util.List;
import java.util.function.Function;

/**
 * 大乐透组合分析服务实现类
 */
@Slf4j
@Service
public class DltCombinationAnalysisServiceImpl implements DltCombinationAnalysisService {

    @Autowired
    private D5Service d5Service;

    @Autowired
    private D6Service d6Service;

    @Autowired
    private D7Service d7Service;

    @Autowired
    private D8Service d8Service;

    @Autowired
    private DltDrawRecordService dltDrawRecordService;

    @Override
    public BallCombinationAnalysisVO analyzeFrontFrontCombination(Integer masterBall, Integer slaveBall) {
        // 参数校验
        validateBallRange(masterBall, 1, 35, "主球（前区）");
        validateBallRange(slaveBall, 1, 35, "随球（前区）");

        // 查询指定组合记录
        D5 targetRecord = d5Service.lambdaQuery()
                .eq(D5::getMasterBallNumber, masterBall)
                .eq(D5::getSlaveBallNumber, slaveBall)
                .one();

        if (targetRecord == null) {
            throw new RuntimeException(String.format("未找到主球（前区）%d和随球（前区）%d的组合记录", masterBall, slaveBall));
        }

        // 查询主球与所有其他球的组合记录
        List<D5> allCombinations = d5Service.lambdaQuery()
                .eq(D5::getMasterBallNumber, masterBall)
                .ne(D5::getSlaveBallNumber, masterBall)  // 排除自身
                .list();

        if (allCombinations.isEmpty()) {
            throw new RuntimeException(String.format("未找到主球（前区）%d的组合记录", masterBall));
        }

        return buildCombinationAnalysisVO(
                targetRecord.getCoefficient(),
                allCombinations,
                D5::getCoefficient,
                D5::getSlaveBallNumber
        );
    }

    @Override
    public BallCombinationAnalysisVO analyzeFrontBackCombination(Integer masterBall, Integer slaveBall) {
        // 参数校验
        validateBallRange(masterBall, 1, 35, "主球（前区）");
        validateBallRange(slaveBall, 1, 12, "随球（后区）");

        // 查询指定组合记录
        D6 targetRecord = d6Service.lambdaQuery()
                .eq(D6::getMasterBallNumber, masterBall)
                .eq(D6::getSlaveBallNumber, slaveBall)
                .one();

        if (targetRecord == null) {
            throw new RuntimeException(String.format("未找到主球（前区）%d和随球（后区）%d的组合记录", masterBall, slaveBall));
        }

        // 查询主球与所有其他球的组合记录
        List<D6> allCombinations = d6Service.lambdaQuery()
                .eq(D6::getMasterBallNumber, masterBall)
                .list();

        if (allCombinations.isEmpty()) {
            throw new RuntimeException(String.format("未找到主球（前区）%d的组合记录", masterBall));
        }

        return buildCombinationAnalysisVO(
                targetRecord.getCoefficient(),
                allCombinations,
                D6::getCoefficient,
                D6::getSlaveBallNumber
        );
    }

    @Override
    public BallCombinationAnalysisVO analyzeBackBackCombination(Integer masterBall, Integer slaveBall) {
        // 参数校验
        validateBallRange(masterBall, 1, 12, "主球（后区）");
        validateBallRange(slaveBall, 1, 12, "随球（后区）");

        // 查询指定组合记录
        D7 targetRecord = d7Service.lambdaQuery()
                .eq(D7::getMasterBallNumber, masterBall)
                .eq(D7::getSlaveBallNumber, slaveBall)
                .one();

        if (targetRecord == null) {
            throw new RuntimeException(String.format("未找到主球（后区）%d和随球（后区）%d的组合记录", masterBall, slaveBall));
        }

        // 查询主球与所有其他球的组合记录
        List<D7> allCombinations = d7Service.lambdaQuery()
                .eq(D7::getMasterBallNumber, masterBall)
                .ne(D7::getSlaveBallNumber, masterBall)  // 排除自身
                .list();

        if (allCombinations.isEmpty()) {
            throw new RuntimeException(String.format("未找到主球（后区）%d的组合记录", masterBall));
        }

        return buildCombinationAnalysisVO(
                targetRecord.getCoefficient(),
                allCombinations,
                D7::getCoefficient,
                D7::getSlaveBallNumber
        );
    }

    @Override
    public BallCombinationAnalysisVO analyzeBackFrontCombination(Integer masterBall, Integer slaveBall) {
        // 参数校验
        validateBallRange(masterBall, 1, 12, "主球（后区）");
        validateBallRange(slaveBall, 1, 35, "随球（前区）");

        // 查询指定组合记录
        D8 targetRecord = d8Service.lambdaQuery()
                .eq(D8::getMasterBallNumber, masterBall)
                .eq(D8::getSlaveBallNumber, slaveBall)
                .one();

        if (targetRecord == null) {
            throw new RuntimeException(String.format("未找到主球（后区）%d和随球（前区）%d的组合记录", masterBall, slaveBall));
        }

        // 查询主球与所有其他球的组合记录
        List<D8> allCombinations = d8Service.lambdaQuery()
                .eq(D8::getMasterBallNumber, masterBall)
                .list();

        if (allCombinations.isEmpty()) {
            throw new RuntimeException(String.format("未找到主球（后区）%d的组合记录", masterBall));
        }

        return buildCombinationAnalysisVO(
                targetRecord.getCoefficient(),
                allCombinations,
                D8::getCoefficient,
                D8::getSlaveBallNumber
        );
    }

    /**
     * 验证球号范围
     */
    private void validateBallRange(Integer ballNumber, int minValue, int maxValue, String ballType) {
        if (ballNumber == null) {
            throw new IllegalArgumentException(ballType + "号码不能为空");
        }
        if (ballNumber < minValue || ballNumber > maxValue) {
            throw new IllegalArgumentException(String.format("%s号码必须在%d-%d范围内，错误值：%d", 
                    ballType, minValue, maxValue, ballNumber));
        }
    }

    /**
     * 构建组合分析结果VO
     */
    private <T> BallCombinationAnalysisVO buildCombinationAnalysisVO(
            Double targetCoefficient,
            List<T> allCombinations,
            Function<T, Double> coefficientGetter,
            Function<T, Integer> ballNumberGetter) {

        // 找出系数最高的球号
        T highest = allCombinations.stream()
                .max(Comparator.comparing(coefficientGetter))
                .orElse(null);

        // 找出系数最低的球号
        T lowest = allCombinations.stream()
                .min(Comparator.comparing(coefficientGetter))
                .orElse(null);

        // 计算平均系数
        double avgCoefficient = allCombinations.stream()
                .mapToDouble(coefficientGetter::apply)
                .average()
                .orElse(0.0);

        // 获取最新开奖期号
        Long latestDrawId = getLatestDrawId();

        return BallCombinationAnalysisVO.builder()
                .faceCoefficient(targetCoefficient)
                .highestBall(highest != null ? ballNumberGetter.apply(highest) : null)
                .highestCoefficient(highest != null ? coefficientGetter.apply(highest) : null)
                .lowestBall(lowest != null ? ballNumberGetter.apply(lowest) : null)
                .lowestCoefficient(lowest != null ? coefficientGetter.apply(lowest) : null)
                .averageCoefficient(avgCoefficient)
                .latestDrawId(latestDrawId)
                .build();
    }

    /**
     * 获取最新开奖期号
     */
    private Long getLatestDrawId() {
        String latestDrawId = dltDrawRecordService.lambdaQuery()
                .orderByDesc(DltDrawRecord::getDrawId)
                .last("LIMIT 1")
                .oneOpt()
                .map(DltDrawRecord::getDrawId)
                .orElse(null);

        if (latestDrawId != null) {
            try {
                return Long.parseLong(latestDrawId);
            } catch (NumberFormatException e) {
                log.warn("开奖期号格式转换失败：{}", latestDrawId);
            }
        }
        return null;
    }
}
