<?php

namespace App\Services;

/**
 * TarneebEngine
 * --------------
 * منطق أوراق اللعب البحت — بدون أي علاقة بقاعدة البيانات أو الشبكة.
 * كل دالة هون pure function (نفس المدخلات = نفس المخرجات دائماً)، عشان يسهل اختبارها.
 *
 * تمثيل الورقة: نص من حرفين-ثلاثة، مثال: "10H", "AS", "KD", "2C"
 * الأنواع (Suits): H=كبة, D=ديناري, S=بستوني, C=سنك
 * الرتب من الأصغر للأكبر: 2,3,4,5,6,7,8,9,10,J,Q,K,A
 */
class TarneebEngine
{
    public const SUITS = ['H', 'D', 'S', 'C'];
    public const RANKS = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A'];

    // الطرنيب = عكس نفس اللون (كبة↔ديناري أحمر، بستوني↔سنك أسود)
    public const TRUMP_PAIR = [
        'H' => 'D',
        'D' => 'H',
        'S' => 'C',
        'C' => 'S',
    ];

    /**
     * توليد دستة كاملة (52 ورقة) مخلوطة عشوائياً.
     */
    public static function freshShuffledDeck(): array
    {
        $deck = [];
        foreach (self::SUITS as $suit) {
            foreach (self::RANKS as $rank) {
                $deck[] = $rank . $suit;
            }
        }
        shuffle($deck);
        return $deck;
    }

    /**
     * توزيع 13 ورقة لكل مقعد (round-robin بادئ بالمقعد بعد الموزّع، منتهي بالموزّع نفسه).
     * آخر ورقة تنوصل للموزّع هي "ورقة القطعة" اللي بتحدد الطرنيب.
     *
     * :return: ['hands' => [seat => [cards]], 'cut_card' => 'XX', 'trump_suit' => 'X']
     */
    public static function dealHand(int $dealerSeat): array
    {
        $deck = self::freshShuffledDeck();

        $hands = [0 => [], 1 => [], 2 => [], 3 => []];
        $order = [];
        for ($i = 1; $i <= 4; $i++) {
            $order[] = ($dealerSeat + $i) % 4; // ينتهي بالموزّع نفسه (لما i=4)
        }

        $cardIndex = 0;
        $cutCard = null;

        for ($round = 0; $round < 13; $round++) {
            foreach ($order as $seat) {
                $card = $deck[$cardIndex];
                $hands[$seat][] = $card;
                $cardIndex++;

                // آخر ورقة توزّع (تروح دايماً للموزّع بالدورة الأخيرة) = ورقة القطعة
                if ($round === 12 && $seat === $dealerSeat) {
                    $cutCard = $card;
                }
            }
        }

        $cutSuit = substr($cutCard, -1);
        $trumpSuit = self::TRUMP_PAIR[$cutSuit];

        return [
            'hands' => $hands,
            'cut_card' => $cutCard,
            'trump_suit' => $trumpSuit,
        ];
    }

    public static function suitOf(string $card): string
    {
        return substr($card, -1);
    }

    public static function rankOf(string $card): string
    {
        return substr($card, 0, -1);
    }

    public static function rankValue(string $card): int
    {
        return array_search(self::rankOf($card), self::RANKS, true);
    }

    /**
     * تحديد فائز لطشة كاملة (4 أوراق).
     * :param cards: ['0' => 'AH', '1' => '3H', '2' => '5D', '3' => 'KH'] (مقعد => ورقة)
     * :param leadSuit: نوع الورقة اللي قادت اللطشة
     * :param trumpSuit: نوع الطرنيب الحالي
     * :return: رقم المقعد الفائز
     */
    public static function resolveTrick(array $cards, string $leadSuit, string $trumpSuit): int
    {
        $trumpCards = array_filter($cards, fn ($card) => self::suitOf($card) === $trumpSuit);

        if (!empty($trumpCards)) {
            // فيه طرنيب باللطشة — الأعلى طرنيب يفوز
            $best = null;
            $bestSeat = null;
            foreach ($trumpCards as $seat => $card) {
                if ($best === null || self::rankValue($card) > self::rankValue($best)) {
                    $best = $card;
                    $bestSeat = $seat;
                }
            }
            return (int) $bestSeat;
        }

        // ما في طرنيب — الأعلى من نوع الورقة القائدة يفوز
        $leadCards = array_filter($cards, fn ($card) => self::suitOf($card) === $leadSuit);
        $best = null;
        $bestSeat = null;
        foreach ($leadCards as $seat => $card) {
            if ($best === null || self::rankValue($card) > self::rankValue($best)) {
                $best = $card;
                $bestSeat = $seat;
            }
        }
        return (int) $bestSeat;
    }

    /**
     * التحقق: هل اللاعب مسموحله يلعب هاي الورقة؟ (لازم يتبع نوع الورقة القائدة لو معه منها)
     */
    public static function isValidPlay(array $playerHand, string $card, ?string $leadSuit): bool
    {
        if (!in_array($card, $playerHand, true)) {
            return false; // الورقة مش معه أصلاً
        }

        if ($leadSuit === null) {
            return true; // هو القائد، أي ورقة تصلح
        }

        $hasLeadSuit = !empty(array_filter($playerHand, fn ($c) => self::suitOf($c) === $leadSuit));

        if (!$hasLeadSuit) {
            return true; // ما معه من نوع القائد، يقدر يلعب أي ورقة
        }

        // معه من نوع القائد — لازم يلعب منه
        return self::suitOf($card) === $leadSuit;
    }

    /**
     * حساب قيمة النقاط لضمن معيّن (5+ تتضاعف).
     */
    public static function bidScoreValue(int $bid): int
    {
        return $bid >= 5 ? $bid * 2 : $bid;
    }

    /**
     * أقل ضمن مسموح بناءً على نقاط اللاعب الحالية (قاعدة الإجبار).
     */
    public static function minimumAllowedBid(int $currentScore): int
    {
        if ($currentScore < 30) {
            return 2;
        }
        return (int) floor($currentScore / 10);
    }
}
