package taurus.util;

import com.taurus.core.entity.ITArray;
import com.taurus.core.entity.ITObject;
import hunan.HuNanPaoDeKuai;

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


public class PaoDeKuaiSuanFaTest {


    /**
     * @param cardInhand 手牌
     * @param card_list  别人打的牌
     * @return 返回可出的牌
     */
    public static ITArray paoDeKuaiOutCardSuanFa(List<CardObj> cardInhand, ITObject card_list, Map<Integer, List<Integer>> seatRemainHistory) {
        System.out.println("机器人手牌 cardInhand: " + cardInhand);
        System.out.println("card_list: " + card_list);

        // 排序手牌
        List<CardObj> sortedHand = new ArrayList<>(cardInhand);
        Collections.sort(sortedHand);
        List<CardObj> playCards;
        // 判断是否是首轮出牌或者上一轮是自己出的牌（对面要不起）
        boolean isFirstTurn = card_list == null || !card_list.containsKey("card_list") ||
                card_list.getTArray("card_list").size() == 0;

        if (isFirstTurn) {
            System.out.println("进入自己先出牌-----------");
            // 自己先出牌
            playCards = playAsFirst(sortedHand);
        } else {
            // 解析对手出的牌
            ITArray opponentCardsArray = card_list.getTArray("card_list");
            List<CardObj> opponentCards = CardUtil.toList(opponentCardsArray);

            // 获取出牌信息
            int minCard = card_list.getInt("min_card");
            int len = card_list.getInt("len");
            int type = card_list.getInt("type");
            int seat = HuNanPaoDeKuai.seat;
            //如果座位号第二次还是自己，代表对面要不起，自己再次出牌
            if (HuNanPaoDeKuai.seat == HuNanPaoDeKuai.guangboseat) {
                Map<Integer, Integer> otherSeatsLastRemain = getOtherSeatsLastRemain(seat, seatRemainHistory);
                boolean hasAnyEqualOne = otherSeatsLastRemain.values().stream()
                        .anyMatch(value -> value == 1);
                if (hasAnyEqualOne) {
                    System.out.println("进入对面只剩下一张1");
                    ITArray itArray = null;
                    CardObj maxSingleCard = CardUtil.findMaxSingleCard(cardInhand);
                    itArray = CardUtil.toTArray1(maxSingleCard);
                    return itArray;
                } else {
                    System.out.println("座位号还是自己，代表对面要不起，自己再次出牌");
                    playCards = playAsFirst(sortedHand);
                    return CardUtil.toTArray(playCards);
                }
            }

            //座位号不是第二次自己的情况
            //对面剩一张牌时，需要出最大牌
            Map<Integer, Integer> otherSeatsLastRemain = getOtherSeatsLastRemain(seat, seatRemainHistory);
            boolean hasAnyEqualOne = otherSeatsLastRemain.values().stream()
                    .anyMatch(value -> value == 1);
            System.out.println("要不起，轮到机器人重新出牌");
            if (hasAnyEqualOne && type == 1) {
                System.out.println("进入对面只剩下一张2");
                ITArray itArray = null;
                CardObj maxSingleCard = CardUtil.findMaxSingleCard(cardInhand);
                itArray = CardUtil.toTArray1(maxSingleCard);
                return itArray;
            } else {
                playCards = playInResponse(sortedHand, minCard, len, opponentCards, type);
                return CardUtil.toTArray(playCards);
            }
        }
        return CardUtil.toTArray(playCards);
    }

    // 获取除当前座位外所有其他座位的最后记录
    public static Map<Integer, Integer> getOtherSeatsLastRemain(int currentSeat, Map<Integer, List<Integer>> seatRemainHistory) {
        Map<Integer, Integer> result = new HashMap<>();

        for (Map.Entry<Integer, List<Integer>> entry : seatRemainHistory.entrySet()) {
            int seat = entry.getKey();
            List<Integer> remainList = entry.getValue();

            // 排除当前座位
            if (seat != currentSeat && !remainList.isEmpty()) {
                // 取list最后一个记录
                int lastRemain = remainList.get(remainList.size() - 1);
                result.put(seat, lastRemain);
            }
        }
        return result;
    }

    /**
     * 响应出牌
     */
    private static List<CardObj> playInResponse(List<CardObj> handCards, int minCard, int len,
                                                List<CardObj> opponentCards, int type) {
        if (handCards.isEmpty()) return new ArrayList<>();

        List<List<CardObj>> possiblePlays = findPossiblePlays(handCards, minCard, len, type);

        if (possiblePlays.isEmpty()) {
            return new ArrayList<>(); // 要不起
        }

        // 选择最优出牌
        return selectBestPlay(possiblePlays, type, handCards.size());
    }

    /**
     * 查找所有可能的出牌
     */
    private static List<List<CardObj>> findPossiblePlays(List<CardObj> handCards, int minCard, int len, int type) {
        List<List<CardObj>> result = new ArrayList<>();

        switch (type) {
            case Config.TYPE_DANPAI:
                result.addAll(findSinglesAbove(handCards, minCard));
                break;
            case Config.TYPE_DUIZI:
                result.addAll(findPairsAbove(handCards, minCard));
                break;
            case Config.TYPE_SHUNZI:
                result.addAll(findStraightsAbove(handCards, minCard, len));
                break;
            case Config.TYPE_LIANDUI:
                result.addAll(findConsecutivePairsAbove(handCards, minCard, len));
                break;
            case Config.TYPE_3_1:
                result.addAll(findTrioWithOneAbove(handCards, minCard));
                break;
            case Config.TYPE_FEIJI:
                result.addAll(findTrioWithPairAbove(handCards, minCard));
                break;
            case Config.TYPE_ZHA:
                result.addAll(findBombsAbove(handCards, minCard));
                break;
            case Config.TYPE_4_2_dui:
                result.addAll(findFourWithTwoPairsAbove(handCards, minCard));
                break;
        }
        // 如果正常牌型找不到，且当前不是炸弹类型，就查找炸弹
        if (result.isEmpty() && type != Config.TYPE_ZHA) {
            result.addAll(findBombsAbove(handCards, -1)); // 找所有炸弹
        }
        return result;
    }

    /**
     * 查找大于指定值的单牌
     */
    private static List<List<CardObj>> findSinglesAbove(List<CardObj> handCards, int minValue) {
        List<List<CardObj>> result = new ArrayList<>();
        for (CardObj card : handCards) {
            if (card.cardMod > minValue) {
                result.add(Arrays.asList(card));
            }
        }
        return result;
    }

    /**
     * 查找大于指定值的对子
     */
    private static List<List<CardObj>> findPairsAbove(List<CardObj> handCards, int minValue) {
        List<List<CardObj>> result = new ArrayList<>();
        Map<Integer, List<CardObj>> valueGroups = groupByValue(handCards);

        for (List<CardObj> cards : valueGroups.values()) {
            if (cards.size() >= 2 && cards.get(0).cardMod > minValue) {
                result.add(Arrays.asList(cards.get(0), cards.get(1)));
            }
        }

        return result;
    }

    /**
     * 按牌值分组
     */
    private static Map<Integer, List<CardObj>> groupByValue(List<CardObj> handCards) {
        Map<Integer, List<CardObj>> groups = new HashMap<>();
        for (CardObj card : handCards) {
            groups.computeIfAbsent(card.cardMod, k -> new ArrayList<>()).add(card);
        }
        return groups;
    }

    /**
     * 查找大于指定值的顺子
     */
    private static List<List<CardObj>> findStraightsAbove(List<CardObj> handCards, int minValue, int length) {
        List<List<CardObj>> result = new ArrayList<>();
        List<Integer> distinctValues = handCards.stream()
                .map(c -> c.cardMod)
                .distinct()
                .sorted()
                .collect(Collectors.toList());

        for (int i = 0; i <= distinctValues.size() - length; i++) {
            if (isConsecutive(distinctValues, i, length) && distinctValues.get(i) > minValue) {
                result.add(buildStraight(handCards, distinctValues.subList(i, i + length)));
            }
        }

        return result;
    }


    /**
     * 庄家先出牌策略
     */
    private static List<CardObj> playAsFirst(List<CardObj> handCards) {
        if (handCards.isEmpty()) return new ArrayList<>();

        Map<Integer, Integer> valueCount = getValueCount(handCards);

        // 策略优先级：顺子 → 三带2 → 单牌 → 对子 → 最小牌
        List<CardObj> play = tryPlayStraight(handCards);
        if (!play.isEmpty()) return play;

        play = tryPlayTrioWithOne(handCards, valueCount);
        if (!play.isEmpty()) return play;

        play = tryPlaySingle(handCards, valueCount);
        if (!play.isEmpty()) return play;

        play = tryPlayPair(handCards, valueCount);
        if (!play.isEmpty()) return play;


        //出最小的牌
        return Arrays.asList(handCards.get(0));
    }

    /**
     * 统计牌值数量
     */
    private static Map<Integer, Integer> getValueCount(List<CardObj> cards) {
        Map<Integer, Integer> countMap = new HashMap<>();
        for (CardObj card : cards) {
            countMap.put(card.cardMod, countMap.getOrDefault(card.cardMod, 0) + 1);
        }
        return countMap;
    }

    /**
     * 尝试出单牌
     */
    private static List<CardObj> tryPlaySingle(List<CardObj> handCards, Map<Integer, Integer> valueCount) {
        System.out.println("尝试出单牌  " + valueCount);
        handCards.sort(Comparator.comparingInt(c -> c.cardMod));

        // 找出所有可能的出牌选择（真单牌 + 对子拆出的单牌）
        List<CardObj> allOptions = new ArrayList<>();

        // 添加所有真单牌
        for (CardObj card : handCards) {
            if (valueCount.get(card.cardMod) == 1) {
                allOptions.add(card);
            }
        }

        // 添加对子拆出的单牌（每个对子取一张）
        for (CardObj card : handCards) {
            if (valueCount.get(card.cardMod) >= 2) {
                // 确保不重复添加同一个对子
                if (allOptions.stream().noneMatch(c -> c.cardMod == card.cardMod)) {
                    allOptions.add(card);
                }
            }
        }

        // 排序选择
        allOptions.sort(Comparator.comparingInt(c -> c.cardMod));

        if (!allOptions.isEmpty()) {
            CardObj bestChoice = allOptions.get(0);
            boolean isFromPair = valueCount.get(bestChoice.cardMod) > 1;

            if (isFromPair) {
                System.out.println("拆对子出最小牌: " + bestChoice);
            } else {
                System.out.println("出真单牌: " + bestChoice);
            }
            return Arrays.asList(bestChoice);
        }
        return Arrays.asList(handCards.get(0));
    }

    /**
     * 尝试出对子
     */
    private static List<CardObj> tryPlayPair(List<CardObj> handCards, Map<Integer, Integer> valueCount) {
        for (CardObj card : handCards) {
            if (valueCount.get(card.cardMod) >= 2) {
                // 返回前两张同值的牌
                return handCards.stream()
                        .filter(c -> c.cardMod == card.cardMod)
                        .limit(2)
                        .collect(Collectors.toList());
            }
        }
        return new ArrayList<>();
    }

    /**
     * 尝试出顺子
     */
    private static List<CardObj> tryPlayStraight(List<CardObj> handCards) {
        final int MIN_STRAIGHT_VALUE = 3;
        final int MAX_STRAIGHT_VALUE = 14;

        List<Integer> distinctValues = handCards.stream()
                .map(c -> c.cardMod)
                .filter(value -> value >= MIN_STRAIGHT_VALUE && value <= MAX_STRAIGHT_VALUE)
                .distinct()
                .sorted()
                .collect(Collectors.toList());

        System.out.println("可用的顺子值: " + distinctValues);

        // 如果可用牌值少于5张，直接返回
        if (distinctValues.size() < 5) {
            return new ArrayList<>();
        }
        int maxPossibleLength = Math.min(distinctValues.size(), 12); // 最多12张

        for (int length = maxPossibleLength; length >= 5; length--) {
            for (int i = 0; i <= distinctValues.size() - length; i++) {
                if (isConsecutive(distinctValues, i, length)) {
                    List<Integer> straightValues = distinctValues.subList(i, i + length);
                    System.out.println("找到" + length + "张顺子: " + straightValues);
                    return buildStraight(handCards, straightValues);
                }
            }
        }

        return new ArrayList<>();
    }

    /**
     * 尝试出三带一
     */
    private static List<CardObj> tryPlayTrioWithOne(List<CardObj> handCards, Map<Integer, Integer> valueCount) {
        // 先按牌值排序（从小到大）
        handCards.sort(Comparator.comparingInt(c -> c.cardMod));

        // 查找最小的三张
        for (CardObj card : handCards) {
            if (valueCount.getOrDefault(card.cardMod, 0) >= 3) {
                List<CardObj> trio = handCards.stream()
                        .filter(c -> c.cardMod == card.cardMod)
                        .limit(3)
                        .collect(Collectors.toList());

                // 寻找两张带牌，优先不破坏对子和顺子牌型
                List<CardObj> sideCards = findBestSideCardsForTrio(handCards, card.cardMod, valueCount);

                if (sideCards.size() >= 2) {
                    List<CardObj> result = new ArrayList<>(trio);
                    result.addAll(sideCards.subList(0, 2));
                    return result;
                }
            }
        }
        return new ArrayList<>();
    }

    private static List<CardObj> findBestSideCardsForTrio(List<CardObj> handCards, int trioValue,
                                                          Map<Integer, Integer> valueCount) {
        List<CardObj> candidateCards = new ArrayList<>();

        // 收集所有不是三张牌本身的牌
        for (CardObj card : handCards) {
            if (card.cardMod != trioValue) {
                candidateCards.add(card);
            }
        }

        // 按优先级选择带牌策略
        List<CardObj> bestChoice = new ArrayList<>();

        // 策略1：优先选择单张牌（不破坏对子）
        List<CardObj> singleCards = findSingleCards(candidateCards, valueCount);
        if (singleCards.size() >= 2) {
            return singleCards.subList(0, Math.min(2, singleCards.size()));
        }

        // 策略2：选择最小的对子（如果只剩一个对子，拆开带）
        List<CardObj> pairCards = findSmallestPair(candidateCards, valueCount);
        if (!pairCards.isEmpty()) {
            if (pairCards.size() >= 2) {
                return pairCards.subList(0, 2); // 带整个对子
            } else {
                bestChoice.add(pairCards.get(0)); // 先带一张
            }
        }

        // 策略3：如果还不够，选择其他单张
        for (CardObj card : candidateCards) {
            if (bestChoice.size() < 2 && !bestChoice.contains(card)) {
                bestChoice.add(card);
            }
        }

        return bestChoice;
    }

    private static List<CardObj> findSingleCards(List<CardObj> cards, Map<Integer, Integer> valueCount) {
        List<CardObj> singleCards = new ArrayList<>();

        // 找出真正的单张牌（没有其他同值的牌）
        for (CardObj card : cards) {
            if (valueCount.getOrDefault(card.cardMod, 0) == 1) {
                singleCards.add(card);
            }
        }

        // 按牌值排序
        singleCards.sort(Comparator.comparingInt(c -> c.cardMod));
        return singleCards;
    }

    private static List<CardObj> findSmallestPair(List<CardObj> cards, Map<Integer, Integer> valueCount) {
        List<CardObj> pairCards = new ArrayList<>();

        // 找出最小的对子
        for (CardObj card : cards) {
            if (valueCount.getOrDefault(card.cardMod, 0) >= 2) {
                List<CardObj> pair = cards.stream()
                        .filter(c -> c.cardMod == card.cardMod)
                        .limit(2)
                        .collect(Collectors.toList());

                // 如果这个对子还没被加入，且比当前选择更小
                if (pairCards.isEmpty() ||
                        (pair.size() >= 2 && pair.get(0).cardMod < pairCards.get(0).cardMod)) {
                    pairCards = pair;
                }
            }
        }

        return pairCards;
    }

    /**
     * 判断是否连续
     */
    private static boolean isConsecutive(List<Integer> values, int start, int length) {
        for (int i = start; i < start + length - 1; i++) {
            if (values.get(i + 1) - values.get(i) != 1) {
                return false;
            }
        }
        return true;
    }

    /**
     * 构建顺子
     */
    private static List<CardObj> buildStraight(List<CardObj> handCards, List<Integer> values) {
        List<CardObj> straight = new ArrayList<>();
        for (int value : values) {
            // 取第一张该值的牌
            for (CardObj card : handCards) {
                if (card.cardMod == value) {
                    straight.add(card);
                    break;
                }
            }
        }
        return straight;
    }

    /**
     * 选择最优出牌
     */
    private static List<CardObj> selectBestPlay(List<List<CardObj>> possiblePlays, int type, int handSize) {
        if (possiblePlays.isEmpty()) return new ArrayList<>();
        //优先出小牌，保留大牌
        possiblePlays.sort((a, b) -> {
            int maxA = a.stream().mapToInt(c -> c.cardMod).max().orElse(0);
            int maxB = b.stream().mapToInt(c -> c.cardMod).max().orElse(0);
            return Integer.compare(maxA, maxB);
        });
        // 手牌少时优先出牌数多的
        if (handSize <= 5) {
            possiblePlays.sort((a, b) -> Integer.compare(b.size(), a.size()));
            return possiblePlays.get(0);
        }
        return possiblePlays.get(0);
    }

    // 各种牌型的查找方法实现
    private static List<List<CardObj>> findConsecutivePairsAbove(List<CardObj> handCards, int minValue, int pairCount) {
        List<List<CardObj>> result = new ArrayList<>();
        if (handCards.isEmpty() || pairCount < 2) return result;

        // 按牌值排序
        handCards.sort(Comparator.comparingInt(c -> c.cardMod));

        Map<Integer, List<CardObj>> valueGroups = new HashMap<>();
        for (CardObj card : handCards) {
            valueGroups.computeIfAbsent(card.cardMod, k -> new ArrayList<>()).add(card);
        }

        // 找出所有至少有2张的牌值（对子）
        List<Integer> pairValues = new ArrayList<>();
        for (Map.Entry<Integer, List<CardObj>> entry : valueGroups.entrySet()) {
            if (entry.getValue().size() >= 2) {
                pairValues.add(entry.getKey());
            }
        }

        if (pairValues.size() < pairCount) return result;

        Collections.sort(pairValues);
        System.out.println("可用的对子值: " + pairValues); // 调试信息

        for (int i = 0; i <= pairValues.size() - pairCount; i++) {
            // 检查是否连续
            boolean isConsecutive = true;
            for (int j = i; j < i + pairCount - 1; j++) {
                if (pairValues.get(j + 1) - pairValues.get(j) != 1) {
                    isConsecutive = false;
                    break;
                }
            }

            // 调试信息
            System.out.println("检查序列: " + pairValues.subList(i, i + pairCount) +
                    ", 连续: " + isConsecutive +
                    ", 最小值: " + pairValues.get(i) + " > " + minValue + " = " + (pairValues.get(i) > minValue));

            // 如果连续且最小值大于指定值
            if (isConsecutive && pairValues.get(i) > minValue) {
                List<CardObj> consecutivePairs = new ArrayList<>();

                // 添加每个对子的前两张牌
                for (int k = i; k < i + pairCount; k++) {
                    int value = pairValues.get(k);
                    List<CardObj> pair = valueGroups.get(value).subList(0, 2);
                    consecutivePairs.addAll(pair);
                }

                result.add(consecutivePairs);
            }
        }

        System.out.println("找到的连对结果: " + result.size()); // 调试信息
        return result;
    }

    private static List<List<CardObj>> findTrioWithOneAbove(List<CardObj> handCards, int minValue) {
        List<List<CardObj>> result = new ArrayList<>();
        Map<Integer, List<CardObj>> valueGroups = groupByValue(handCards);

        // 找出所有三张的牌
        List<Integer> trioValues = new ArrayList<>();
        for (Map.Entry<Integer, List<CardObj>> entry : valueGroups.entrySet()) {
            if (entry.getValue().size() >= 3 && entry.getKey() > minValue) {
                trioValues.add(entry.getKey());
            }
        }

        Collections.sort(trioValues);

        for (int trioValue : trioValues) {
            List<CardObj> trio = valueGroups.get(trioValue).subList(0, 3);

            // 找出所有可带的牌（排除三张的牌值）
            List<CardObj> availableCards = new ArrayList<>();
            for (Map.Entry<Integer, List<CardObj>> entry : valueGroups.entrySet()) {
                if (entry.getKey() != trioValue) {
                    availableCards.addAll(entry.getValue());
                }
            }

            if (availableCards.size() < 2) continue;

            // 找出所有可能的两个牌组合（可以是一对或两个单牌）
            findTrioCombinations(result, trio, availableCards);
        }

        return result;
    }

    /**
     * 找出所有可能的三带2组合
     */
    private static void findTrioCombinations(List<List<CardObj>> result,
                                             List<CardObj> trio,
                                             List<CardObj> availableCards) {
        availableCards.sort(CardObj::compareTo);

        Set<String> combinationSet = new HashSet<>();

        for (int i = 0; i < availableCards.size() - 1; i++) {
            CardObj card1 = availableCards.get(i);

            for (int j = i + 1; j < availableCards.size(); j++) {
                CardObj card2 = availableCards.get(j);

                if (card1.card != card2.card) {
                    String comboKey;
                    if (card1.cardMod <= card2.cardMod) {
                        comboKey = card1.cardMod + "-" + card2.cardMod;
                    } else {
                        comboKey = card2.cardMod + "-" + card1.cardMod;
                    }

                    if (!combinationSet.contains(comboKey)) {
                        combinationSet.add(comboKey);

                        List<CardObj> play = new ArrayList<>(trio);
                        play.add(card1);
                        play.add(card2);
                        result.add(play);
                    }
                }
            }
        }
    }

    private static List<List<CardObj>> findTrioWithPairAbove(List<CardObj> handCards, int minValue) {
        List<List<CardObj>> result = new ArrayList<>();
        // 飞机逻辑
        return result;
    }


    private static List<List<CardObj>> findBombsAbove(List<CardObj> handCards, int minValue) {
        List<List<CardObj>> result = new ArrayList<>();

        // 先按牌值排序
        handCards.sort(Comparator.comparingInt(c -> c.cardMod));

        // 统计每种牌值的数量
        Map<Integer, List<CardObj>> valueGroups = new HashMap<>();
        for (CardObj card : handCards) {
            valueGroups.computeIfAbsent(card.cardMod, k -> new ArrayList<>()).add(card);
        }

        // 找出所有炸弹（4张或以上相同牌值）
        for (Map.Entry<Integer, List<CardObj>> entry : valueGroups.entrySet()) {
            int cardValue = entry.getKey();
            List<CardObj> cards = entry.getValue();

            // 如果是炸弹（4张或以上）且大于minValue
            if (cards.size() >= 4 && cardValue > minValue) {
                result.add(cards);
            }
        }

        return result;
    }

    private static List<List<CardObj>> findFourWithTwoSinglesAbove(List<CardObj> handCards, int minValue) {
        List<List<CardObj>> result = new ArrayList<>();
        // 实现四带二单牌逻辑
        return result;
    }

    private static List<List<CardObj>> findFourWithTwoPairsAbove(List<CardObj> handCards, int minValue) {
        List<List<CardObj>> result = new ArrayList<>();
        // 实现四带二对子逻辑
        return result;
    }
}
