package taurus.util;

import hunan.HuNanChangSha;

import java.util.*;

public class TinHuGang {


    /**
     * 判断是否能杠牌（检查杠牌后是否立即听牌）
     */
    public static boolean canGang(List<Integer> handCards, int card, boolean isMingGang) {
        int type = card / 100;
        int value = card % 100;

        System.out.println("\n检查" + (isMingGang ? "明" : "暗") + "杠" + value + getTypeName(type) + ":");

        // 检查是否符合杠牌条件
        int count = Collections.frequency(handCards, card);

        if (isMingGang) {
            // 明杠：手牌中需要有三张相同的牌
            if (count < 3) {
                System.out.println("  手牌中没有三张相同的" + value + getTypeName(type) + "，不能明杠");
                return false;
            }
            System.out.println("  发现三张" + value + getTypeName(type) + "，可以明杠");
        } else {
            // 暗杠：手牌中需要有四张相同的牌
            if (count < 4) {
                System.out.println("  手牌中没有四张相同的" + value + getTypeName(type) + "，不能暗杠");
                return false;
            }
            System.out.println("  发现四张" + value + getTypeName(type) + "，可以暗杠");
        }

        // 检查杠牌后是否立即听牌（杠牌后手牌本身就是听牌状态）
        return canTingImmediatelyAfterGang(handCards, card, isMingGang);
    }

    /**
     * 检查杠牌后是否能立即听牌
     */
    private static boolean canTingImmediatelyAfterGang(List<Integer> handCards, int gangCard, boolean isMingGang) {
        int type = gangCard / 100;
        int value = gangCard % 100;

        System.out.println("\n模拟" + (isMingGang ? "明" : "暗") + "杠" + value + getTypeName(type) + ":");

        // 1. 模拟杠牌：移除手牌中的牌
        List<Integer> afterGang = new ArrayList<>(handCards);

        if (isMingGang) {
            // 明杠：移除手牌中的三张牌
            for (int i = 0; i < 3; i++) {
                afterGang.remove(Integer.valueOf(gangCard));
            }
            // 杠牌后手牌数：13张 → 10张
        } else {
            // 暗杠：移除手牌中的四张牌
            for (int i = 0; i < 4; i++) {
                afterGang.remove(Integer.valueOf(gangCard));
            }
            // 暗杠后需要补牌，但这里先不处理
        }

        Collections.sort(afterGang);

        System.out.println("  杠后手牌(" + afterGang.size() + "张): " + convertToReadable(afterGang));

        // 2. 检查是否需要258将
        boolean needs258 = !checkSuitCount(afterGang);
        if (needs258) {
            System.out.println("  花色牌数不足10张，需要258做将");
        }

        // 3. 检查杠牌后手牌本身是否就是听牌状态
        // 注意：杠牌后手牌数是10张，这10张牌本身应该是听牌状态
        // 也就是说，随便摸一张牌（任何牌）都能胡牌

        System.out.println("\n  检查杠后手牌是否听牌:");

        if (afterGang.size() != 10) {
            System.out.println("  手牌数不是10张，不符合听牌条件");
            return false;
        }

        // 检查这10张牌是否听牌
        boolean canTing = checkIfHandIsTingPai(afterGang, needs258);

        if (canTing) {
            System.out.println("  ✓ 杠后手牌是听牌状态！");

            // 显示听哪些牌
            Set<Integer> tingCards = getTingCards(afterGang, needs258);
            if (!tingCards.isEmpty()) {
                System.out.print("  听" + tingCards.size() + "张牌: ");
                List<String> tingStrs = new ArrayList<>();
                for (int tingCard : tingCards) {
                    tingStrs.add((tingCard%100) + getTypeName(tingCard/100));
                }
                System.out.println(String.join(", ", tingStrs));
            }
            return true;
        } else {
            System.out.println("  ✗ 杠后手牌不是听牌状态");
            return false;
        }
    }

    /**
     * 检查手牌是否处于听牌状态
     */
    private static boolean checkIfHandIsTingPai(List<Integer> hand, boolean needs258) {
        if (hand.size() != 10) {
            return false;
        }

        // 听牌状态：再摸任何一张牌都能胡牌
        // 我们需要检查是否至少有一张牌能让这手牌胡牌
        Set<Integer> allCards = getAllCards();
        int tingCount = 0;

        for (int testCard : allCards) {
            List<Integer> tempHand = new ArrayList<>(hand);
            tempHand.add(testCard);

            if (canHu(tempHand, needs258)) {
                tingCount++;
            }
        }

        System.out.println("  可胡" + tingCount + "张牌");
        return tingCount > 0;
    }

    /**
     * 获取听哪些牌
     */
    private static Set<Integer> getTingCards(List<Integer> hand, boolean needs258) {
        Set<Integer> tingCards = new HashSet<>();

        if (hand.size() != 10) {
            return tingCards;
        }

        Set<Integer> allCards = getAllCards();

        for (int testCard : allCards) {
            List<Integer> tempHand = new ArrayList<>(hand);
            tempHand.add(testCard);

            if (canHu(tempHand, needs258)) {
                tingCards.add(testCard);
            }
        }

        return tingCards;
    }

    /**
     * 检查手牌是否能胡牌
     */
    private static boolean canHu(List<Integer> handCards, boolean needs258) {
        // 手牌排序
        List<Integer> sorted = new ArrayList<>(handCards);
        Collections.sort(sorted);

        // 胡牌时手牌数必须是3n+2
        if (sorted.size() != 11 && sorted.size() != 14) {
            return false;
        }

        // 检查七对子
        if (checkQiDuiZi(sorted)) {
            // 七对子不需要258将
            return true;
        }

        // 如果需要258将，检查普通胡牌（必须有258将）
        if (needs258) {
            return checkNormalHuWith258(sorted);
        } else {
            // 不需要258将，检查普通胡牌
            return checkNormalHu(sorted);
        }
    }

    /**
     * 检查七对子
     */
    private static boolean checkQiDuiZi(List<Integer> handCards) {
        if (handCards.size() != 14) return false;

        Map<Integer, Integer> countMap = new HashMap<>();
        for (int card : handCards) {
            countMap.put(card, countMap.getOrDefault(card, 0) + 1);
        }

        // 检查是否都是对子
        for (int count : countMap.values()) {
            if (count != 2) {
                return false;
            }
        }

        return true;
    }

    /**
     * 检查普通胡牌（必须有258将）
     */
    private static boolean checkNormalHuWith258(List<Integer> handCards) {
        // 尝试每种258作为将牌
        for (int card : handCards) {
            int value = card % 100;
            // 检查是否是258
            if (value == 2 || value == 5 || value == 8) {
                // 检查是否有至少2张相同的牌做将
                int count = Collections.frequency(handCards, card);
                if (count >= 2) {
                    // 移除将牌
                    List<Integer> remaining = new ArrayList<>(handCards);
                    for (int i = 0; i < 2; i++) {
                        remaining.remove(Integer.valueOf(card));
                    }

                    // 检查剩余牌是否能组成顺子/刻子
                    if (canGroup(remaining)) {
                        return true;
                    }
                }
            }
        }

        return false;
    }

    /**
     * 检查普通胡牌（不需要258将）
     */
    private static boolean checkNormalHu(List<Integer> handCards) {
        return checkNormalHuRecursive(new ArrayList<>(handCards), false);
    }

    private static boolean checkNormalHuRecursive(List<Integer> handCards, boolean hasJiang) {
        if (handCards.isEmpty()) {
            return true; // 所有牌都分组成功
        }

        Collections.sort(handCards);

        // 统计第一张牌的数量
        int firstCard = handCards.get(0);
        int count = Collections.frequency(handCards, firstCard);

        // 尝试作为刻子（三张相同）
        if (count >= 3) {
            List<Integer> remaining = new ArrayList<>(handCards);
            for (int i = 0; i < 3; i++) {
                remaining.remove(Integer.valueOf(firstCard));
            }
            if (checkNormalHuRecursive(remaining, hasJiang)) {
                return true;
            }
        }

        // 尝试作为顺子（三张连续）
        int type = firstCard / 100;
        int value = firstCard % 100;

        if (type < 4 && value <= 7) { // 字牌和8、9不能组成顺子
            int second = type * 100 + (value + 1);
            int third = type * 100 + (value + 2);

            if (handCards.contains(second) && handCards.contains(third)) {
                List<Integer> remaining = new ArrayList<>(handCards);
                remaining.remove(Integer.valueOf(firstCard));
                remaining.remove(Integer.valueOf(second));
                remaining.remove(Integer.valueOf(third));
                if (checkNormalHuRecursive(remaining, hasJiang)) {
                    return true;
                }
            }
        }

        // 尝试作为将（对子）- 只能有一个将
        if (!hasJiang && count >= 2) {
            List<Integer> remaining = new ArrayList<>(handCards);
            remaining.remove(Integer.valueOf(firstCard));
            remaining.remove(Integer.valueOf(firstCard));
            if (checkNormalHuRecursive(remaining, true)) {
                return true;
            }
        }

        return false;
    }

    /**
     * 检查牌是否能组成顺子或刻子
     */
    private static boolean canGroup(List<Integer> cards) {
        if (cards.isEmpty()) {
            return true; // 所有牌都分组成功
        }

        List<Integer> sorted = new ArrayList<>(cards);
        Collections.sort(sorted);

        int firstCard = sorted.get(0);
        int count = Collections.frequency(sorted, firstCard);

        // 尝试作为刻子（三张相同）
        if (count >= 3) {
            List<Integer> remaining = new ArrayList<>(sorted);
            for (int i = 0; i < 3; i++) {
                remaining.remove(Integer.valueOf(firstCard));
            }
            if (canGroup(remaining)) {
                return true;
            }
        }

        // 尝试作为顺子（三张连续）
        int type = firstCard / 100;
        int value = firstCard % 100;

        if (type < 4 && value <= 7) { // 字牌和8、9不能组成顺子
            int second = type * 100 + (value + 1);
            int third = type * 100 + (value + 2);

            if (sorted.contains(second) && sorted.contains(third)) {
                List<Integer> remaining = new ArrayList<>(sorted);
                remaining.remove(Integer.valueOf(firstCard));
                remaining.remove(Integer.valueOf(second));
                remaining.remove(Integer.valueOf(third));
                if (canGroup(remaining)) {
                    return true;
                }
            }
        }

        return false;
    }

    /**
     * 检查手牌花色牌数是否>=10张
     */
    private static boolean checkSuitCount(List<Integer> hand) {
        Map<Integer, Integer> suitCount = new HashMap<>();
        for (int card : hand) {
            int type = card / 100;
            if (type < 4) {
                suitCount.put(type, suitCount.getOrDefault(type, 0) + 1);
            }
        }

        for (int count : suitCount.values()) {
            if (count >= 10) {
                return true;
            }
        }

        return false;
    }

    /**
     * 获取所有麻将牌
     */
    private static Set<Integer> getAllCards() {
        Set<Integer> allCards = new HashSet<>();
        for (int type = 1; type <= 3; type++) {
            for (int value = 1; value <= 9; value++) {
                allCards.add(type * 100 + value);
            }
        }
        return allCards;
    }

    /**
     * 转换为可读格式
     */
    private static String convertToReadable(List<Integer> cards) {
        StringBuilder sb = new StringBuilder();
        for (int card : cards) {
            int type = card / 100;
            int value = card % 100;
            sb.append(value).append(getTypeName(type)).append(" ");
        }
        return sb.toString();
    }

    /**
     * 获取牌型名称
     */
    private static String getTypeName(int type) {
        switch(type) {
            case 1: return "万";
            case 2: return "筒";
            case 3: return "条";
            default: return "字";
        }
    }
}