package taurus.util;

import java.util.*;
import java.util.stream.Collectors;

public class zuixin {

    // 长沙麻将特殊规则：二五八将
    private static final Set<Integer> JIANG_PAIS;

    public boolean isTinAi = false;

    static {
        Set<Integer> jiangSet = new HashSet<>();
        jiangSet.add(2);
        jiangSet.add(5);
        jiangSet.add(8);
        JIANG_PAIS = Collections.unmodifiableSet(jiangSet);
    }

    public static void main(String[] args) {
        System.out.println("=== 长沙麻将测试（含碰杠吃牌） ===");
        zuixin ai = new zuixin();

        // 测试1：普通手牌
        System.out.println("\n=== 测试1：普通14张牌 ===");
        PlayerState state1 = new PlayerState();
        state1.handCards = Arrays.asList(204, 206, 205, 205, 203, 109, 108, 107, 107, 106, 103, 102, 101, 101);
        int discard1 = ai.findBestDiscard(state1);
        System.out.println("推荐出牌: " + ai.formatCard(discard1));
    }

    /**
     * 主方法：根据完整玩家状态推荐出牌
     */
    public int findBestDiscard(PlayerState state) {
        System.out.println("\n=== 长沙麻将AI出牌分析 ===");
        System.out.println("手牌(" + state.handCards.size() + "张): " + formatCards(state.handCards));

        // 分析手牌结构
        analyzeHandStructure(state.handCards);

        long startTime = System.currentTimeMillis();

        // 获取可出的牌（手牌中的唯一牌）
        Map<Integer, Double> results = new HashMap<>();
        Set<Integer> uniqueCards = new HashSet<>(state.handCards);

        // 如果只剩一张牌，直接返回
        if (state.handCards.size() == 1) {
            int onlyCard = state.handCards.get(0);
            System.out.println("只剩一张牌，必须出: " + formatCard(onlyCard));
            return onlyCard;
        }

        for (int card : uniqueCards) {
            // 评估打出这张牌的得分
            double score = evaluateDiscard(card, state);
            results.put(card, score);

            System.out.printf("打出 %s: 评分=%.1f%n", formatCard(card), score);
        }

        // 找出最佳出牌
        int bestCard = -1;
        double bestScore = Double.NEGATIVE_INFINITY;

        for (Map.Entry<Integer, Double> entry : results.entrySet()) {
            if (entry.getValue() > bestScore) {
                bestScore = entry.getValue();
                bestCard = entry.getKey();
            }
        }

        long endTime = System.currentTimeMillis();
        System.out.printf("\n分析耗时: %dms%n", (endTime - startTime));

        if (bestCard != -1) {
            System.out.println("\n🎯 AI推荐出牌: " + formatCard(bestCard));
        }

        return bestCard;
    }

    /**
     * 分析手牌结构
     */
    private void analyzeHandStructure(List<Integer> hand) {
        System.out.println("\n=== 手牌结构分析 ===");

        // 按花色分组
        Map<Integer, List<Integer>> suitGroups = new HashMap<>();
        for (int card : hand) {
            int suit = getCardType(card);
            suitGroups.putIfAbsent(suit, new ArrayList<>());
            suitGroups.get(suit).add(getCardValue(card));
        }

        // 分析每个花色
        for (Map.Entry<Integer, List<Integer>> entry : suitGroups.entrySet()) {
            int suit = entry.getKey();
            List<Integer> values = entry.getValue();
            Collections.sort(values);

            System.out.printf("  %s: %s%n",
                    getSuitName(suit),
                    values.stream().map(String::valueOf).collect(Collectors.joining(" ")));
        }
    }

    /**
     * 评估打出某张牌的得分
     */
    private double evaluateDiscard(int card, PlayerState state) {
        List<Integer> hand = state.handCards;
        int type = getCardType(card);
        int value = getCardValue(card);
        double score = 0.0;

        System.out.printf("\n=== 评估 %s ===%n", formatCard(card));

        // 1. 检查原始数量
        int originalCount = Collections.frequency(hand, card);
        System.out.printf("  原始数量: %d张%n", originalCount);

        // 2. 258将牌保护（非常重要）
        if (JIANG_PAIS.contains(value)) {
            System.out.println("  258将牌: 扣30分");
            score -= 30.0;

            // 258将对子特别重要
            if (originalCount >= 2) {
                System.out.println("  258将对子: 额外扣20分");
                score -= 20.0;
            }
        }

        // 3. 检查是否是对子/刻子（非258将）
        if (originalCount >= 2 && !JIANG_PAIS.contains(value)) {
            if (originalCount >= 3) {
                System.out.println("  刻子: 扣40分");
                score -= 40.0;
            } else {
                // 检查是否冗余对子
                boolean isRedundant = isRedundantPairInCurrentHand(card, hand);
                if (isRedundant) {
                    System.out.println("  冗余对子: 加25分鼓励打出");
                    score += 25.0;
                } else {
                    System.out.println("  对子: 扣15分");
                    score -= 15.0;
                }
            }
        }

        // 4. 检查这张牌的搭子情况
        DaziInfo daziInfo = analyzeDazi(card, hand);
        System.out.printf("  搭子分析: %s%n", daziInfo.getDescription());

        // 根据搭子情况调整分数
        if (daziInfo.isLonely()) {
            System.out.println("  完全孤立: 加20分");
            score += 20.0;
        } else if (daziInfo.getGoodDaziCount() == 0) {
            System.out.println("  无好搭子: 加15分");
            score += 15.0;
        } else if (daziInfo.getGoodDaziCount() == 1) {
            System.out.println("  有1个好搭子: 加5分");
            score += 5.0;
        } else {
            System.out.printf("  有%d个好搭子: 扣15分（保留价值高）%n", daziInfo.getGoodDaziCount());
            score -= 15.0;
        }

        // 5. 边张评估
        if (value == 1 || value == 9) {
            System.out.println("  边张: 加15分（利用率低）");
            score += 15.0;
        }

        // 6. 检查是否在完整顺子中且多余
        if (isInCompleteSequenceAndRedundant(card, hand)) {
            System.out.println("  顺子中多余: 加20分鼓励打出");
            score += 20.0;
        }

        // 7. 花色分布
        int suitCount = countSuitCards(type, hand);
        if (suitCount <= 2) {
            System.out.printf("  花色孤立(只有%d张): 加10分%n", suitCount);
            score += 10.0;
        }

        return score;
    }

    /**
     * 搭子信息类
     */
    private static class DaziInfo {
        private boolean lonely = true;
        private int goodDaziCount = 0;
        private List<String> descriptions = new ArrayList<>();

        public void addGoodDazi(String desc) {
            goodDaziCount++;
            descriptions.add(desc);
            lonely = false;
        }

        public void addBadDazi(String desc) {
            descriptions.add(desc);
            lonely = false;
        }

        public boolean isLonely() {
            return lonely;
        }

        public int getGoodDaziCount() {
            return goodDaziCount;
        }

        public String getDescription() {
            if (lonely) return "完全孤立";
            return String.join(", ", descriptions) + " (好搭子:" + goodDaziCount + "个)";
        }
    }

    /**
     * 分析搭子情况
     */
    private DaziInfo analyzeDazi(int card, List<Integer> hand) {
        int type = getCardType(card);
        int value = getCardValue(card);
        DaziInfo info = new DaziInfo();

        // 获取同花色牌（不包括要评估的这张牌本身）
        List<Integer> sameSuit = hand.stream()
                .filter(c -> getCardType(c) == type && c != card)
                .collect(Collectors.toList());

        if (sameSuit.isEmpty()) {
            return info; // 完全孤立
        }

        // 检查相邻牌
        boolean hasNeighbor = false;
        for (int other : sameSuit) {
            int otherValue = getCardValue(other);
            int diff = Math.abs(otherValue - value);

            if (diff == 1) {
                hasNeighbor = true;
                // 相邻搭子是好搭子
                int min = Math.min(value, otherValue);
                int max = Math.max(value, otherValue);
                info.addGoodDazi(formatCard(type * 100 + min) + formatCard(type * 100 + max));
            } else if (diff == 2) {
                // 隔张搭子，检查是否有中间牌
                int middleValue = Math.min(value, otherValue) + 1;
                int middleCard = type * 100 + middleValue;
                if (hand.contains(middleCard)) {
                    // 实际能形成顺子，是好搭子
                    info.addGoodDazi("顺子" + formatCard(type * 100 + Math.min(value, otherValue)) +
                            formatCard(middleCard) +
                            formatCard(type * 100 + Math.max(value, otherValue)));
                } else {
                    // 单纯的隔张搭子，质量一般
                    info.addBadDazi("隔张" + formatCard(type * 100 + Math.min(value, otherValue)) +
                            formatCard(type * 100 + Math.max(value, otherValue)));
                }
            }
        }

        // 如果没有相邻牌但有对子，对子也是好搭子
        if (!hasNeighbor) {
            int count = Collections.frequency(hand, card);
            if (count >= 2) {
                info.addGoodDazi("对子");
            }
        }

        return info;
    }

    /**
     * 检查是否冗余对子（在当前手牌中）
     */
    private boolean isRedundantPairInCurrentHand(int card, List<Integer> hand) {
        int type = getCardType(card);
        int value = getCardValue(card);

        // 检查是否在顺子中
        if (value >= 3) {
            // 检查是否能形成前顺子
            int prev1 = type * 100 + (value - 1);
            int prev2 = type * 100 + (value - 2);
            if (hand.contains(prev1) && hand.contains(prev2)) {
                // 比如3万对子，且有12万
                return true;
            }
        }

        if (value <= 7) {
            // 检查是否能形成后顺子
            int next1 = type * 100 + (value + 1);
            int next2 = type * 100 + (value + 2);
            if (hand.contains(next1) && hand.contains(next2)) {
                // 比如7万对子，且有89万
                return true;
            }
        }

        if (value >= 2 && value <= 8) {
            // 检查是否能形成中顺子
            int prev = type * 100 + (value - 1);
            int next = type * 100 + (value + 1);
            if (hand.contains(prev) && hand.contains(next)) {
                // 比如4万对子，且有3万和5万
                return true;
            }
        }

        return false;
    }

    /**
     * 检查是否在完整顺子中且多余
     */
    private boolean isInCompleteSequenceAndRedundant(int card, List<Integer> hand) {
        int type = getCardType(card);
        int value = getCardValue(card);
        int count = Collections.frequency(hand, card);

        if (count <= 1) return false; // 只有一张，不多余

        // 检查是否能形成顺子
        if (value >= 1 && value <= 7) {
            int next1 = type * 100 + (value + 1);
            int next2 = type * 100 + (value + 2);
            if (hand.contains(next1) && hand.contains(next2)) {
                // 比如有2张1万，且有2万和3万
                return true;
            }
        }

        if (value >= 3 && value <= 9) {
            int prev1 = type * 100 + (value - 1);
            int prev2 = type * 100 + (value - 2);
            if (hand.contains(prev1) && hand.contains(prev2)) {
                // 比如有2张3万，且有1万和2万
                return true;
            }
        }

        return false;
    }

    /**
     * 统计同花色的牌数
     */
    private int countSuitCards(int suit, List<Integer> hand) {
        int count = 0;
        for (int card : hand) {
            if (getCardType(card) == suit) {
                count++;
            }
        }
        return count;
    }

    private String getSuitName(int suit) {
        switch(suit) {
            case 1: return "万";
            case 2: return "筒";
            case 3: return "条";
            default: return "字牌";
        }
    }

    /**
     * 获取牌值
     */
    private int getCardValue(int card) {
        return card % 10;
    }

    /**
     * 获取牌类型
     */
    private int getCardType(int card) {
        return card / 100;
    }

    /**
     * 格式化单张牌
     */
    String formatCard(int card) {
        int type = card / 100;
        int value = card % 10;
        switch (type) {
            case 1:
                return value + "万";
            case 2:
                return value + "筒";
            case 3:
                return value + "条";
            default:
                return "字牌";
        }
    }

    /**
     * 格式化牌列表
     */
    private String formatCards(List<Integer> cards) {
        return cards.stream()
                .sorted()
                .map(this::formatCard)
                .collect(Collectors.joining(" "));
    }

    /**
     * 玩家状态类
     */
    public static class PlayerState {
        public List<Integer> handCards = new ArrayList<>();
        public List<List<Integer>> pongGroups = new ArrayList<>();
        public List<List<Integer>> gangGroups = new ArrayList<>();
        public List<List<Integer>> chiGroups = new ArrayList<>();
        public boolean isZhuang = false;

        public void addPongGroup(List<Integer> group) {
            pongGroups.add(new ArrayList<>(group));
        }

        public void addGangGroup(List<Integer> group) {
            gangGroups.add(new ArrayList<>(group));
        }

        public void addChiGroup(List<Integer> group) {
            chiGroups.add(new ArrayList<>(group));
        }

        public int getPongGroupCount() {
            return pongGroups.size();
        }

        public int getGangGroupCount() {
            return gangGroups.size();
        }

        public int getChiGroupCount() {
            return chiGroups.size();
        }

        public int getTotalGroupCount() {
            return getPongGroupCount() + getGangGroupCount() + getChiGroupCount();
        }
    }
}