package com.xy.xyaicpzs.util;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

/**
 * 大乐透中奖规则计算器
 * 根据预测号码和开奖号码计算中奖等级和奖金
 */
@Slf4j
public class DltPrizeCalculator {

    /**
     * 中奖结果
     */
    @Data
    public static class PrizeResult {
        /** 中奖等级 */
        private String prizeLevel;
        /** 奖金（元） */
        private Long bonus;
        /** 前区命中个数 */
        private int frontMatches;
        /** 后区命中个数 */
        private int backMatches;
        
        public PrizeResult(String prizeLevel, Long bonus, int frontMatches, int backMatches) {
            this.prizeLevel = prizeLevel;
            this.bonus = bonus;
            this.frontMatches = frontMatches;
            this.backMatches = backMatches;
        }
    }

    /**
     * 计算大乐透中奖结果
     * 
     * @param predictNumbers 预测号码数组，格式：[前区5个号码, 后区2个号码]
     * @param drawNumbers 开奖号码数组，格式：[前区5个号码, 后区2个号码]
     * @param prizePool 奖池金额（单位：亿元），用于判断奖金档位
     * @return 中奖结果
     */
    public static PrizeResult calculatePrize(Integer[] predictNumbers, Integer[] drawNumbers, Double prizePool) {
        if (predictNumbers == null || drawNumbers == null) {
            throw new IllegalArgumentException("预测号码和开奖号码不能为空");
        }
        
        if (predictNumbers.length != 7 || drawNumbers.length != 7) {
            throw new IllegalArgumentException("号码数组长度必须为7（前区5个+后区2个）");
        }

        // 分离前区和后区号码
        Integer[] predictFront = Arrays.copyOfRange(predictNumbers, 0, 5);
        Integer[] predictBack = Arrays.copyOfRange(predictNumbers, 5, 7);
        Integer[] drawFront = Arrays.copyOfRange(drawNumbers, 0, 5);
        Integer[] drawBack = Arrays.copyOfRange(drawNumbers, 5, 7);

        // 计算前区命中个数
        int frontMatches = calculateMatches(predictFront, drawFront);
        
        // 计算后区命中个数
        int backMatches = calculateMatches(predictBack, drawBack);

        log.debug("前区命中{}个，后区命中{}个，奖池金额：{}亿元", frontMatches, backMatches, prizePool);

        // 根据中奖规则判断奖级
        String prizeLevel = determinePrizeLevel(frontMatches, backMatches);
        Long bonus = calculateBonus(prizeLevel, prizePool);

        return new PrizeResult(prizeLevel, bonus, frontMatches, backMatches);
    }
    
    /**
     * 计算大乐透中奖结果（兼容旧版本，默认奖池为0）
     * 
     * @param predictNumbers 预测号码数组，格式：[前区5个号码, 后区2个号码]
     * @param drawNumbers 开奖号码数组，格式：[前区5个号码, 后区2个号码]
     * @return 中奖结果
     */
    public static PrizeResult calculatePrize(Integer[] predictNumbers, Integer[] drawNumbers) {
        return calculatePrize(predictNumbers, drawNumbers, 0.0);
    }

    /**
     * 计算两个号码数组的匹配个数
     */
    private static int calculateMatches(Integer[] predict, Integer[] draw) {
        Set<Integer> drawSet = new HashSet<>(Arrays.asList(draw));
        int matches = 0;
        
        for (Integer number : predict) {
            if (number != null && drawSet.contains(number)) {
                matches++;
            }
        }
        
        return matches;
    }

    /**
     * 根据前区和后区命中个数判断中奖等级
     * 
     * 中奖规则：
     * 一等奖：5+2（前区5个+后区2个）
     * 二等奖：5+1（前区5个+后区1个）
     * 三等奖：5+0 或 4+2（前区5个 或 前区4个+后区2个）
     * 四等奖：4+1（前区4个+后区1个）
     * 五等奖：4+0 或 3+2（前区4个 或 前区3个+后区2个）
     * 六等奖：3+1 或 2+2（前区3个+后区1个 或 前区2个+后区2个）
     * 七等奖：3+0 或 1+2 或 2+1 或 0+2（前区3个 或 前区1个+后区2个 或 前区2个+后区1个 或 后区2个）
     */
    private static String determinePrizeLevel(int frontMatches, int backMatches) {
        if (frontMatches == 5 && backMatches == 2) {
            return "一等奖";
        } else if (frontMatches == 5 && backMatches == 1) {
            return "二等奖";
        } else if ((frontMatches == 5 && backMatches == 0) || 
                   (frontMatches == 4 && backMatches == 2)) {
            return "三等奖";
        } else if (frontMatches == 4 && backMatches == 1) {
            return "四等奖";
        } else if ((frontMatches == 4 && backMatches == 0) || 
                   (frontMatches == 3 && backMatches == 2)) {
            return "五等奖";
        } else if ((frontMatches == 3 && backMatches == 1) || 
                   (frontMatches == 2 && backMatches == 2)) {
            return "六等奖";
        } else if ((frontMatches == 3 && backMatches == 0) || 
                   (frontMatches == 1 && backMatches == 2) || 
                   (frontMatches == 2 && backMatches == 1) || 
                   (frontMatches == 0 && backMatches == 2)) {
            return "七等奖";
        } else {
            return "未中奖";
        }
    }

    /**
     * 根据中奖等级和奖池金额计算奖金
     * 
     * 奖金规则（基本投注2元）：
     * - 奖池≥8亿元时为高奖金档
     * - 奖池<8亿元时为低奖金档
     * 
     * 一等奖：浮动奖金，500万封顶（不区分奖池）
     * 二等奖：浮动奖金，500万封顶（不区分奖池）
     * 三等奖：奖池≥8亿 6666元，奖池<8亿 5000元
     * 四等奖：奖池≥8亿 380元，奖池<8亿 300元
     * 五等奖：奖池≥8亿 200元，奖池<8亿 150元
     * 六等奖：奖池≥8亿 18元，奖池<8亿 15元
     * 七等奖：奖池≥8亿 7元，奖池<8亿 5元
     * 
     * @param prizeLevel 中奖等级
     * @param prizePool 奖池金额（单位：亿元）
     * @return 奖金（元）
     */
    private static Long calculateBonus(String prizeLevel, Double prizePool) {
        // 判断奖池档位：8亿元
        boolean isHighPrizePool = (prizePool != null && prizePool >= 8.0);
        
        switch (prizeLevel) {
            case "一等奖":
                return 5000000L; // 500万元封顶（浮动奖金）
            case "二等奖":
                return 5000000L; // 500万元封顶（浮动奖金）
            case "三等奖":
                return isHighPrizePool ? 6666L : 5000L;
            case "四等奖":
                return isHighPrizePool ? 380L : 300L;
            case "五等奖":
                return isHighPrizePool ? 200L : 150L;
            case "六等奖":
                return isHighPrizePool ? 18L : 15L;
            case "七等奖":
                return isHighPrizePool ? 7L : 5L;
            default:
                return 0L; // 未中奖
        }
    }
    
    /**
     * 根据中奖等级计算奖金（兼容旧版本，默认奖池为0）
     * @deprecated 请使用 calculateBonus(String prizeLevel, Double prizePool)
     */
    @Deprecated
    private static Long calculateBonus(String prizeLevel) {
        return calculateBonus(prizeLevel, 0.0);
    }

    /**
     * 验证号码格式是否正确
     */
    public static boolean validateNumbers(Integer[] numbers) {
        if (numbers == null || numbers.length != 7) {
            return false;
        }

        // 验证前区号码（1-35）
        for (int i = 0; i < 5; i++) {
            if (numbers[i] == null || numbers[i] < 1 || numbers[i] > 35) {
                return false;
            }
        }

        // 验证后区号码（1-12）
        for (int i = 5; i < 7; i++) {
            if (numbers[i] == null || numbers[i] < 1 || numbers[i] > 12) {
                return false;
            }
        }

        // 验证前区号码不能重复
        Set<Integer> frontSet = new HashSet<>();
        for (int i = 0; i < 5; i++) {
            if (!frontSet.add(numbers[i])) {
                return false; // 有重复
            }
        }

        // 验证后区号码不能重复
        if (numbers[5].equals(numbers[6])) {
            return false;
        }

        return true;
    }

    /**
     * 格式化号码显示
     */
    public static String formatNumbers(Integer[] numbers) {
        if (numbers == null || numbers.length != 7) {
            return "无效号码";
        }

        StringBuilder sb = new StringBuilder();
        
        // 前区号码
        sb.append("前区: ");
        for (int i = 0; i < 5; i++) {
            if (i > 0) sb.append(" ");
            sb.append(String.format("%02d", numbers[i]));
        }
        
        // 后区号码
        sb.append(" | 后区: ");
        for (int i = 5; i < 7; i++) {
            if (i > 5) sb.append(" ");
            sb.append(String.format("%02d", numbers[i]));
        }
        
        return sb.toString();
    }
}
