package taurus.util;

import java.util.*;

public class ChangshaWinSplitCard {

    // 统计牌数
    public static int[][] countTiles(List<Integer> cardInHand) {
        int[][] counts = new int[5][10]; // 类型×值

        //预计算牌型和牌值 避免重复计算
        for (Integer card : cardInHand) {
            if (card == 0) {
                continue;
            }
            int suitIndex = card / 100 - 1;  // 牌型索引
            int cardValue = card % 100;      // 牌面值
            counts[suitIndex][cardValue]++;
        }
        return counts;
    }

    // 检测不带精湖
    public static int checkNormalHu(List<Integer> cardInHand, Map<String, Object> map) {
        if (cardInHand == null || cardInHand.isEmpty()) {
            //throw new IllegalArgumentException("手牌不能为空");
        }
        
        String info = "";
        int[][] counts = countTiles(cardInHand);
        int group = 0;
        int handSizeDiv3 = cardInHand.size() / 3;//缓存计算结果 避免重复计算
        // 尝试找将牌
        for (int type = 0; type < 5; type++) {
            int max = 9;
            for (int value = 1; value <= max; value++) {
                if (counts[type][value] >= 2 && (value == 2 || value == 5 || value == 8)) {
                    // 找到可能的将牌
                    counts[type][value] -= 2;
                    group = checkMelds(counts, handSizeDiv3, map);
                    if (group == 0) { // 剩余12张牌需要组成4个顺子或刻子
                        counts[type][value] += 2;
                        return 0;
                    }
                    counts[type][value] += 2;
                } else {
                    group = checkMelds(counts, handSizeDiv3 + 1, map);

                    if (group == 0) { // 剩余12张牌需要组成4个顺子或刻子
                        counts[type][value] += 2;
                        return 0;
                    }
                }
            }
        }

        List<Integer> cardResiue = (List<Integer>) map.get("cardResiue");
        
        //空指针检查
        if (cardResiue != null && cardResiue.size() > 1) {
            for (int i = 0; i < cardResiue.size() - 1; i++) {
                Integer currentCard = cardResiue.get(i);
                Integer nextCard = cardResiue.get(i + 1);
                
                //缓存牌值计算结果
                int currentValue = currentCard % 100;
                if (currentCard.equals(nextCard) && (currentValue == 2 || currentValue == 5 || currentValue == 8)) {
                    cardResiue.remove(i);
                    cardResiue.remove(i);
                    break;
                }
            }
        }

        haveBetween(cardResiue, cardInHand);

        System.out.println("可以打出的牌：" + cardResiue);
        System.out.println("总共差几手牌：" + map.get("remainingMelds"));

        return group;
    }

    // 递归检查是否可以组成顺子或刻子
    public static int checkMelds(int[][] counts, int remainingMelds, Map<String, Object> map) {
        if (remainingMelds == 0) {
            return 0;
        }

        // 优先检查刻子
        for (int type = 0; type < 5; type++) {
            int max = 9;
            for (int value = 1; value <= max; value++) {
                if (counts[type][value] >= 3) {
                    counts[type][value] -= 3;
                    try {
                        if (checkMelds(counts, remainingMelds - 1, map) == 0) {
                            counts[type][value] += 3;
                            return 0;
                        }
                    } finally {
                        //确保状态回滚
                        counts[type][value] += 3;
                    }
                }
            }
        }

        // 检查顺子
        for (int type = 0; type < 5; type++) {
            int max = 7;

            for (int value = 1; value <= max; value++) {
                if (counts[type][value] >= 1 && counts[type][value + 1] >= 1 && counts[type][value + 2] >= 1) {

                    counts[type][value]--;
                    counts[type][value + 1]--;
                    counts[type][value + 2]--;

                    try {
                        if (checkMelds(counts, remainingMelds - 1, map) == 0) {
                            return 0;
                        }
                    } finally {
                        //确保状态回滚
                        counts[type][value]++;
                        counts[type][value + 1]++;
                        counts[type][value + 2]++;
                    }
                }
            }
        }
        // 判断孤章
        List<Integer> cardResiue = convertCountToCards(counts);

        if (!cardResiue.isEmpty()) {
            // 优先保留连续张
            removeConsecutivePairs1(cardResiue);
        }

        if (!cardResiue.isEmpty()) {
            // 第二优先保留对子
            removeConsecutivePairsTwo(cardResiue);
        }
        
        // 最后保留坎张
        // 如果坎张，为空则取边张
        if (!cardResiue.isEmpty()) {
            List<Integer> tmp3 = new ArrayList<>(cardResiue); //使用构造函数替代addAll
            removeConsecutivePairs2(cardResiue);
            if (cardResiue.isEmpty()) {
                // 取边站
                cardResiue = qubianzhang(tmp3);
            }
        }

        //合并重复的条件判断
        if (remainingMelds == 0) {
            map.put("remainingMelds", 0);
            map.put("cardResiue", "已经胡牌");
        } else if (map.get("remainingMelds") == null) {
            map.put("remainingMelds", remainingMelds);
        }
        if (map.get("cardResiue") == null) {
            map.put("cardResiue", cardResiue);
        }
        //提取重复逻辑为私有方法 添加空指针检查
        if (cardResiue != null && cardResiue.size() > 1) {
            for (int i = 0; i < cardResiue.size() - 1; i++) {
                Integer currentCard = cardResiue.get(i);
                Integer nextCard = cardResiue.get(i + 1);
                
                int currentValue = currentCard % 100;
                if (currentCard.equals(nextCard) && is258JiangValue(currentValue)) {
                    cardResiue.remove(i);
                    cardResiue.remove(i);
                    if (remainingMelds >= 2) {
                        remainingMelds--;
                    }
                    break;
                }
            }
        }
        //添加类型安全检查和空指针防护
        Object remainingMeldsObj = map.get("remainingMelds");
        if (remainingMeldsObj != null && 
            Integer.parseInt(remainingMeldsObj.toString()) >= remainingMelds && 
            !cardResiue.isEmpty()) {
            // 如果没有258做将则需要进入这里判断

            if (remainingMelds == 1 && cardResiue.size() == 2) {
                processSpecialCase(cardResiue, remainingMelds, map);
            } else {
                map.put("remainingMelds", remainingMelds);
                map.put("cardResiue", cardResiue);
            }
        }

        return remainingMelds;
    }

    public static void removeConsecutivePairsTwo(List<Integer> cards) {
        if (cards == null || cards.size() < 2) {
            return;
        }
        
        //使用TreeSet自动排序并去重
        Set<Integer> uniqueCards = new TreeSet<>(cards);
        List<Integer> result = new ArrayList<>();
        
        //过滤掉成对的牌
        Map<Integer, Integer> cardCount = new HashMap<>();
        for (Integer card : cards) {
            cardCount.put(card, cardCount.getOrDefault(card, 0) + 1);
        }
        
        for (Integer card : uniqueCards) {
            if (cardCount.get(card) == 1) {
                result.add(card);
            }
        }

        cards.clear();
        cards.addAll(result);
    }

    // 辅助方法
    public static void removeConsecutivePairs1(List<Integer> cards) {
        if (cards == null || cards.size() < 2) {
            return;
        }

        //使用TreeSet自动排序
        List<Integer> sorted = new ArrayList<>(new TreeSet<>(cards));
        List<Integer> result = new ArrayList<>();
        int i = 0;

        while (i < sorted.size()) {
            //缓存计算结果
            int currentValue = sorted.get(i) % 100;
            boolean isEdgeCard = currentValue == 1 || currentValue == 8;
            
            if (!isEdgeCard && i < sorted.size() - 1 && sorted.get(i + 1) - sorted.get(i) == 1) {
                // 跳过这对连续牌
                i += 2;
            } else {
                // 保留这张牌
                result.add(sorted.get(i));
                i++;
            }
        }

        cards.clear();
        cards.addAll(result);
    }

    public static List<Integer> qubianzhang(List<Integer> cards) {
        if (cards == null || cards.isEmpty()) {
            return new ArrayList<>();
        }
        
        List<Integer> result = new ArrayList<>();
        //使用增强for循环提高可读性
        for (Integer card : cards) {
            int value = card % 100;
            if (value == 1 || value == 9) {
                result.add(card);
            }
        }
        return result;
    }

    public static void removeConsecutivePairs2(List<Integer> cards) {
        if (cards == null || cards.size() < 2) {
            return;
        }

        //使用TreeSet自动排序
        List<Integer> sorted = new ArrayList<>(new TreeSet<>(cards));
        
        //使用Set替代布尔数组
        Set<Integer> cardsToRemove = new HashSet<>();

        // 找出所有隔张（相差2的牌对，如1和3、2和4等）
        for (int i = 0; i < sorted.size(); i++) {
            Integer currentCard = sorted.get(i);
            if (cardsToRemove.contains(currentCard)) {
                continue; //如果这张牌已被标记删除 跳过
            }
            
            for (int j = i + 1; j < sorted.size(); j++) {
                Integer nextCard = sorted.get(j);
                if (cardsToRemove.contains(nextCard)) {
                    continue; //如果这张牌已被标记删除 跳过
                }
                
                int diff = nextCard - currentCard;
                
                if (diff == 2 && sorted.size() > 2) {
                    //找到隔张 标记删除
                    cardsToRemove.add(currentCard);
                    cardsToRemove.add(nextCard);

                    //提前检查边界条件
                    if (j + 1 < sorted.size()) {
                        int nextNextValue = sorted.get(j + 1) % 100;
                        if (nextNextValue == 2 || nextNextValue == 5 || nextNextValue == 6) {
                            cardsToRemove.remove(currentCard);
                            cardsToRemove.remove(nextCard);
                        }
                    }
                    break;//找到一对就跳出内层循环
                } else if (diff > 2) {
                    break;
                }
            }
        }

        // 构建结果列表（保留未标记删除的牌）
        List<Integer> result = new ArrayList<>();
        for (Integer card : sorted) {
            if (!cardsToRemove.contains(card)) {
                result.add(card);
            }
        }

        cards.clear();
        cards.addAll(result);
    }

    public static void haveBetween(List<Integer> cards, List<Integer> cardInHand) {
        //添加空指针检查
        if (cards == null || cardInHand == null || 
            cards.size() <= 1 || cardInHand.size() <= 1) {
            return;
        }

        // 创建要删除的牌列表
        Set<Integer> toRemove = new HashSet<>();

        //缓存手牌的牌型信息，避免重复计算
        Map<Integer, Integer> handCardTypes = new HashMap<>();
        for (int handCard : cardInHand) {
            handCardTypes.put(handCard, handCard / 100);
        }

        //遍历cards中的每一张牌
        for (int card : cards) {
            int cardType = card / 100;
            
            //检查是否有与手牌形成靠章的牌
            for (int handCard : cardInHand) {
                //先检查牌型是否相同 再计算差值
                if (handCardTypes.get(handCard) == cardType) {
                    //定义靠章规则：相同、相邻或隔一张
                    int diff = Math.abs(card - handCard);
                    if (diff == 1 || diff == 2) {
                        toRemove.add(card);
                        break;//找到一个匹配就可以跳出内层循环
                    }
                }
            }
        }

        // 只有当cards中还有多于1张牌时才执行删除
        if (cards.size() - toRemove.size() > 0) {
            cards.removeAll(toRemove);
        }

        System.out.println("删除的牌: " + toRemove);
        System.out.println("cards剩余: " + cards);
    }

    // 从二维数组counts还原到手牌列表
    private static List<Integer> convertCountToCards(int[][] counts) {
        if (counts == null) {
            return new ArrayList<>();
        }
        
        List<Integer> cardInHand = new ArrayList<>();

        // counts数组结构：[类型索引][牌值]
        // 类型索引: 0=万, 1=筒, 2=条, 3=风, 4=箭 (根据您的编码规则)
        // 牌值: 1-9表示牌面值

        for (int suitIdx = 0; suitIdx < counts.length && suitIdx < 5; suitIdx++) {
            int suit = suitIdx + 1; // 还原百位数 (1,2,3,4,5)

            for (int value = 1; value < counts[suitIdx].length && value <= 9; value++) {
                int count = counts[suitIdx][value];
                
                int baseCard = suit * 100 + value;
                for (int i = 0; i < count; i++) {
                    cardInHand.add(baseCard);
                }
            }
        }

        return cardInHand;
    }

    public static List<Integer> checktingpai(List<Integer> cardhand) {
        //添加参数验证
        if (cardhand == null || cardhand.isEmpty()) {
            return new ArrayList<>();
        }
        
        List<Integer> tpcards = new ArrayList<>();
        List<Integer> tmphc = new ArrayList<>(cardhand);
        
        //缓存可能的胡牌列表
        List<Integer> candidateCards = new ArrayList<>();
        for (int j = 101; j <= 109; j++) candidateCards.add(j);
        for (int j = 201; j <= 209; j++) candidateCards.add(j);
        
        for (int i = 0; i < cardhand.size(); i++) {
            Integer tmpcard = tmphc.remove(0); //使用泛型避免强制转换
            
            //批量检查候选牌
            for (Integer candidate : candidateCards) {
                WinCard win = new WinCard(tmphc, candidate);
                if (win.tryWin() && !tpcards.contains(tmpcard)) {
                    tpcards.add(tmpcard);
                    break;//找到一个就可以跳出循环
                }
            }
            
            tmphc.add(tmpcard);
        }
        return tpcards;
    }

    // 分析最优出牌
    public static List<Integer> analyzeBestDiscard(List<Integer> cardInHand) {
        if (cardInHand == null || cardInHand.isEmpty()) {
            return new ArrayList<>();
        }

        // 听牌
        // 返回要打的牌，打后可以听牌
        List<Integer> checktingpai = checktingpai(cardInHand);
        System.out.println("打出这种牌后可以听牌 " + checktingpai);
        Map<String, Object> map = new HashMap<>();
        Map<String, List<Integer>> jmap = new HashMap<>();// 对将map
        checkNormalHu(cardInHand, map);

        List<Integer> suggested = (List<Integer>) map.get("cardResiue");
        
        if (suggested == null) {
            suggested = new ArrayList<>();
        }

        // 返回要打的牌，打后可以听牌
        List<Integer> zuizhongchupai = new ArrayList<>();
        
        //提取交集逻辑为独立方法
        findIntersectionCards(checktingpai, suggested, zuizhongchupai);

        // 推荐打几个牌都能听牌，需要判断打哪个听的牌更多
        if (checktingpai.size() > 1 && zuizhongchupai.isEmpty()) {
            zuizhongchupai.addAll(checktingpai);
        }

        // 如果判断听牌和递归出来的牌不一样 优先以听牌为准
        if (zuizhongchupai.isEmpty()) {
            zuizhongchupai.addAll(checktingpai);
        }

        // 如果判断最后打出牌还未听牌，就用递归判断的牌
        if (zuizhongchupai.isEmpty()) {
            zuizhongchupai.addAll(suggested);
        }
        System.out.println("zuizhongchupai" + zuizhongchupai);
        return zuizhongchupai.isEmpty() ? new ArrayList<>() : zuizhongchupai;
    }

    public static Integer selectBestCardRemove258(List<Integer> cards) {
        if (cards == null || cards.isEmpty()) {
            return null;
        }

        // 如果只有一张牌，直接返回
        if (cards.size() == 1) {
            return cards.get(0);
        }

        // 创建非258牌的列表
        List<Integer> non258Cards = new ArrayList<>();
        List<Integer> is258Cards = new ArrayList<>();

        // 分类：258牌和非258牌
        for (Integer card : cards) {
            if (is258Jiang(card)) {
                is258Cards.add(card);
            } else {
                non258Cards.add(card);
            }
        }

        System.out.println("258将牌: " + is258Cards);
        System.out.println("非258牌: " + non258Cards);
        //判断是否手牌有其他对将

        // 优先从非258牌中选
        if (!non258Cards.isEmpty()) {
            return selectBestSingleCard(non258Cards);
        }

        // 如果没有非258牌，从258牌中选
        if (!is258Cards.isEmpty()) {
            return selectBestSingleCard(is258Cards);
        }

        return null;
    }

    // 检测是否满足258做将的条件
    private static boolean is258Jiang(int card) {
        // 提取牌的类型和值
        int type = card / 100; // 百位数：1-万，2-筒，3-条，4-风，5-箭
        int value = card % 100; // 个位数：牌面值

        // 只有万、筒、条有258做将的限制
        if (type >= 1 && type <= 3) {
            // 258做将：二万(102)、五万(105)、八万(108)
            // 二筒(202)、五筒(205)、八筒(208)
            // 二条(302)、五条(305)、八条(308)
            return value == 2 || value == 5 || value == 8;
        }
        return false;
    }
    
    //提取258将值判断逻辑
    private static boolean is258JiangValue(int value) {
        return value == 2 || value == 5 || value == 8;
    }
    
    //提取特殊处理逻辑
    private static void processSpecialCase(List<Integer> cardResiue, int remainingMelds, Map<String, Object> map) {
        int diff = Math.abs(cardResiue.get(0) - cardResiue.get(1));
        if (diff > 1) {
            map.put("remainingMelds", remainingMelds + 1);
            if (cardResiue.size() > 1) {
                cardResiue.remove(0);
            }
            map.put("cardResiue", cardResiue);
        } else {
            int cardValue = cardResiue.get(0) % 100;
            if (is258JiangValue(cardValue)) {
                //删除符合258做将的牌
                if (cardResiue.size() > 1) {
                    cardResiue.remove(0);
                }
                map.put("remainingMelds", remainingMelds);
            } else {
                map.put("remainingMelds", remainingMelds);
            }
            map.put("cardResiue", cardResiue);
        }
    }
    
    //提取交集查找逻辑
    private static void findIntersectionCards(List<Integer> checktingpai, List<Integer> suggested, List<Integer> result) {
        if (checktingpai.isEmpty()) return;
        
        for (Integer card : checktingpai) {
            if (suggested.contains(card)) {
                result.add(card);
            }
        }
    }

    // 从候选牌中选出最优的一张牌（优先边张1或9）
    public static Integer selectBestSingleCard(List<Integer> cards) {
        if (cards == null || cards.isEmpty()) {
            return null;
        }
        
        //使用Stream API简化查找逻辑
        return cards.stream()
            .filter(card -> {
                int value = card % 100;
                return value == 1 || value == 9;
            })
            .findFirst()
            .orElseGet(() -> cards.stream()
                .filter(card -> {
                    int value = card % 100;
                    return value == 2 || value == 8;
                })
                .findFirst()
                .orElse(cards.get(0)));
    }

    // 主方法
    public static void main(String[] args) {
        // 测试用例：没有258将牌的情况
        List<Integer> test1 = new ArrayList<Integer>();
//		test1 = Arrays.asList(208, 204, 203, 202, 107, 106, 105, 103, 102, 101, 103);
//		test1.add(208);
//		test1.add(204);
//		test1.add(203);
//		test1.add(202);
//		test1.add(107);
//		test1.add(106);
//		test1.add(105);
//		test1.add(103);
//		test1.add(102);
//		test1.add(101);
//		test1.add(101);

//        test1.add(208);
//        test1.add(207);
//        test1.add(205);
//        test1.add(204);
//        test1.add(203);
//        test1.add(202);
//        test1.add(201);
//        test1.add(109);
//        test1.add(108);
//        test1.add(106);
//        test1.add(205);

//        test1.add(205);
//        test1.add(203);
//        test1.add(202);
//        test1.add(201);
//        test1.add(204);
//        test1.add(107);
//        test1.add(106);
//        test1.add(105);

//        test1.add(201);
//        test1.add(107);
//        test1.add(107);
//        test1.add(104);

//        test1.add(101);
//        test1.add(102);
//        test1.add(103);
//        test1.add(104);
//        test1.add(109);
//        test1.add(201);
//        test1.add(204);
//        test1.add(204);
//        test1.add(206);
//        test1.add(207);
//        test1.add(207);
//        test1.add(209);
//        test1.add(209);
//        test1.add(209);

//
//
        test1.add(209);
        test1.add(208);
        test1.add(208);
        test1.add(207);
        test1.add(205);
        test1.add(107);
        test1.add(107);
        test1.add(105);
        test1.add(104);
        test1.add(103);

        test1.add(103);

        test1.add(103);
        test1.add(102);
        test1.add(104);
//        test1.add(103);
//        test1.add(102);

        System.out.println("手牌：" + test1);
        List<Integer> bestDiscard = analyzeBestDiscard(test1);
//        Integer integer = selectBestCardByPriority(bestDiscard);
        Integer integer1 = selectBestCardRemove258(bestDiscard);

        Map<String, Object> mapSS = new HashMap<>();
        checkNormalHu(test1, mapSS);
        System.out.println("map:" + mapSS);

        System.out.println("ww" + integer1);
//        if (!bestDiscard.isEmpty()) {
//            System.out.println("建议出牌：" + bestDiscard.get(0));
//        } else {
//            System.out.println("没有出牌建议");
//        }
    }
}