package taurus.util;

import hunan.HuNanChangSha;

import java.util.*;

public class TinHuPeng {

    /**
     * 判断是否能碰牌（包含碰牌后的听牌检查）
     */
    public  boolean canPeng(List<Integer> handCards, int card) {
        int type = card / 100;
        int value = card % 100;

        if (type >= 4) return false; // 字牌不能碰（长沙麻将没有字牌）

        System.out.println("\n要碰的牌: " + value + getTypeName(type));
        System.out.println("当前手牌数量: " + handCards.size() + "张");

        // 检查基本碰牌条件：手牌至少有2张相同的牌
        if (!canPengBasic(handCards, card)) {
            System.out.println("  基本碰牌条件不满足：手牌没有2张" + value + getTypeName(type));
            return false;
        }
        System.out.println("  ✓ 手牌有2张" + value + getTypeName(type) + "，可以碰");
       ChangShaSuanFaTest.isPeng = true;
        // 检查碰牌后是否能听牌
        return canTingAfterPengAndDiscard(handCards, card);
    }

    /**
     * 检查基本碰牌条件
     */
    private  boolean canPengBasic(List<Integer> handCards, int card) {
        // 碰牌：手牌有2张相同的牌，别人打出第3张
        int count = 0;
        for (int c : handCards) {
            if (c == card) {
                count++;
            }
        }
        return count >= 2;
    }

    /**
     * 检查碰牌并打出一张后是否能听牌
     */
    private  boolean canTingAfterPengAndDiscard(List<Integer> handCards, int pengCard) {
        // 1. 模拟碰牌：移除两张相同的牌，碰的牌不加入手牌
        List<Integer> afterPeng = new ArrayList<>(handCards);

        // 移除2张相同的牌
        int removed = 0;
        for (int i = 0; i < handCards.size() && removed < 2; i++) {
            if (handCards.get(i) == pengCard) {
                afterPeng.remove(Integer.valueOf(pengCard));
                removed++;
            }
        }
        Collections.sort(afterPeng);

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

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

        // 3. 根据碰后手牌数确定目标手牌数
        // 碰牌前后手牌数变化：碰前N张 -> 碰后(N-2)张 -> 打后(N-3)张
        int targetSizeAfterDiscard = afterPeng.size() - 1;
        System.out.println("  目标手牌数: " + targetSizeAfterDiscard);

        // 4. 尝试打每一张不同的牌
        Set<Integer> uniqueCards = new HashSet<>(afterPeng);
        boolean foundTing = false;

        for (int discardCard : uniqueCards) {
            List<Integer> afterDiscard = new ArrayList<>(afterPeng);
            afterDiscard.remove(Integer.valueOf(discardCard));
            Collections.sort(afterDiscard);

            int discardType = discardCard / 100;
            int discardValue = discardCard % 100;

            System.out.print("\n    打" + discardValue + getTypeName(discardType) +
                    " → 剩余" + afterDiscard.size() + "张: " +
                    convertToReadable(afterDiscard));

            // 5. 检查打牌后是否能听牌
            boolean canTing = checkCanTing(afterDiscard, needs258, targetSizeAfterDiscard);

            if (canTing) {
                HuNanChangSha.isTinPeng = true;
                System.out.println(" ✓ 听牌！");
                foundTing = true;

                // 分析听牌详情
                analyzeTingDetails(afterDiscard, needs258);
            } else {
                System.out.println(" ✗ 不听");
            }
        }

        return foundTing;
    }

    /**
     * 检查手牌是否能听牌
     */
    private  boolean checkCanTing(List<Integer> hand, boolean needs258, int targetSize) {
        if (hand.size() != targetSize) {
            System.out.print(" [手牌数" + hand.size() + "≠目标" + targetSize + "]");
            return false;
        }

        // 获取所有可能的牌
        Set<Integer> allCards = getAllCards();

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

            // 检查是否能胡牌
            if (canHu(tempHand, needs258)) {
                return true;
            }
        }

        return false;
    }

    /**
     * 检查手牌是否能胡牌（考虑258将要求）
     */
    private  boolean canHu(List<Integer> handCards, boolean needs258) {
        // 手牌排序
        List<Integer> sorted = new ArrayList<>(handCards);
        Collections.sort(sorted);

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

        // 检查七对子（特殊胡牌）
        if (checkQiDuiZi(sorted)) {
            // 七对子不需要258将
            return true;
        }

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

    /**
     * 分析听牌详情
     */
    private  void analyzeTingDetails(List<Integer> hand, boolean needs258) {
        Set<Integer> tingCards = new HashSet<>();
        Set<Integer> allCards = getAllCards();

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

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

        if (!tingCards.isEmpty()) {
            System.out.print("      听" + tingCards.size() + "张牌: ");
            List<String> tingCardStrs = new ArrayList<>();
            for (int card : tingCards) {
                int type = card / 100;
                int value = card % 100;
                tingCardStrs.add(value + getTypeName(type));
            }
            System.out.println(String.join(", ", tingCardStrs));
        }
    }

    /**
     * 检查手牌花色牌数是否>=10张
     */
    private  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);
            }
        }

        // 检查是否有某种花色>=10张
        for (int count : suitCount.values()) {
            if (count >= 10) {
                return true; // 有花色>=10张，不需要258将
            }
        }

        return false; // 没有花色>=10张，需要258将
    }

    /**
     * 检查七对子
     */
    private  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  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  boolean checkNormalHu(List<Integer> handCards) {
        return checkNormalHuRecursive(new ArrayList<>(handCards), false);
    }

    private  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  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;
    }

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

    /**
     * 转换为可读格式
     */
    private  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  String getTypeName(int type) {
        switch(type) {
            case 1: return "万";
            case 2: return "筒";
            case 3: return "条";
            default: return "字";
        }
    }

    /**
     * 手牌分析类
     */
     class HandAnalysis {
        int keziCount = 0;     // 刻子数量
        int pairCount = 0;     // 对子数量
        int shunziCount = 0;   // 顺子数量
        int singleCount = 0;   // 单张数量
        List<Integer> singles = new ArrayList<>(); // 单张列表
        boolean has258Jiang = false; // 是否有258将
        List<Integer> pairs = new ArrayList<>(); // 对子列表（value）
    }
}
