<?php

namespace App\Services;

/**
 * TrixEngine
 * -----------
 * منطق أوراق تريكس البحت — بدون أي علاقة بقاعدة البيانات.
 *
 * التسميات الخمسة:
 *  - diamonds       (ديناري)     — تجنب أخذ الديناري       — -10 لكل ورقة
 *  - tricks         (لطوش)       — تجنب أخذ أي لطشة        — -15 لكل لطشة
 *  - king_of_hearts (شيخ الكبة)  — تجنب أخذ ملك الكبة KH   — -75 لو أخذه
 *  - queens         (بنات)       — تجنب أخذ الملكات (Q)    — -25 لكل بنت
 *  - trix           (تركس)       — لعبة ترصيف موجبة        — +200/+150/+100/+50 حسب ترتيب الخلوص
 */
class TrixEngine
{
    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 JACK_INDEX = 9; // موقع J بمصفوفة RANKS — نقطة انطلاق ترصيف التركس

    public const CONTRACTS = ['diamonds', 'tricks', 'king_of_hearts', 'queens', 'trix'];

    public static function freshShuffledDeck(): array
    {
        $deck = [];
        foreach (self::SUITS as $suit) {
            foreach (self::RANKS as $rank) {
                $deck[] = $rank . $suit;
            }
        }
        shuffle($deck);
        return $deck;
    }

    /**
     * توزيع 13 ورقة لكل مقعد (بدون حاجة لموزّع/ورقة قطعة — تريكس ما فيها طرنيب).
     */
    public static function dealFresh(): array
    {
        $deck = self::freshShuffledDeck();
        $hands = [0 => [], 1 => [], 2 => [], 3 => []];

        foreach ($deck as $i => $card) {
            $hands[$i % 4][] = $card;
        }

        return $hands;
    }

    /**
     * إيجاد المقعد اللي معه سبعة الكبة (يحدد الملك الأول بالماتش فقط).
     */
    public static function findSevenOfHeartsSeat(array $hands): int
    {
        foreach ($hands as $seat => $cards) {
            if (in_array('7H', $cards, true)) {
                return (int) $seat;
            }
        }
        // احتياطي نظري (لازم توجد دايماً بدستة كاملة) — أول مقعد
        return 0;
    }

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

    /**
     * فائز لطشة — تريكس ما فيها طرنيب إطلاقاً، الأعلى من نوع الورقة القائدة يفوز دايماً.
     */
    public static function resolveTrick(array $cards, string $leadSuit): int
    {
        $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 isValidTrickPlay(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;
    }

    // ==============================================================
    // 🃏 منطق تسمية التركس (ترصيف، مو لطش)
    // ==============================================================

    /**
     * هل الورقة قابلة للترصيف حالياً؟
     * :param layout: ['H' => ['low' => 9, 'high' => 9] | null, 'D' => null, ...]
     */
    public static function isValidTrixPlacement(array $layout, string $card): bool
    {
        $suit = self::suitOf($card);
        $rankIdx = self::rankValue($card);
        $suitLayout = $layout[$suit] ?? null;

        if ($suitLayout === null) {
            // النوع لسا ما انفتح — لازم تكون J بالضبط
            return $rankIdx === self::JACK_INDEX;
        }

        return $rankIdx === $suitLayout['low'] - 1 || $rankIdx === $suitLayout['high'] + 1;
    }

    public static function applyTrixPlacement(array $layout, string $card): array
    {
        $suit = self::suitOf($card);
        $rankIdx = self::rankValue($card);
        $suitLayout = $layout[$suit] ?? null;

        if ($suitLayout === null) {
            $layout[$suit] = ['low' => $rankIdx, 'high' => $rankIdx];
            return $layout;
        }

        if ($rankIdx === $suitLayout['low'] - 1) {
            $layout[$suit]['low'] = $rankIdx;
        } else {
            $layout[$suit]['high'] = $rankIdx;
        }

        return $layout;
    }

    /**
     * هل عند اللاعب أي ورقة قابلة للترصيف حالياً؟ (لتحديد لازم يلعب أو يمرّر)
     */
    public static function hasAnyValidTrixPlay(array $layout, array $hand): bool
    {
        foreach ($hand as $card) {
            if (self::isValidTrixPlacement($layout, $card)) {
                return true;
            }
        }
        return false;
    }

    // ==============================================================
    // 💯 حساب النقاط
    // ==============================================================

    /**
     * نقاط تسمية من التسميات الأربعة السلبية (بناءً على الأوراق اللي أخدها كل مقعد).
     * :param capturedBySeat: ['0' => ['10D','7D'], '1' => [], ...]
     */
    public static function scoreTrickContract(string $contract, array $capturedBySeat): array
    {
        $scores = ['0' => 0, '1' => 0, '2' => 0, '3' => 0];

        foreach ($capturedBySeat as $seat => $cards) {
            $penalty = match ($contract) {
                'diamonds' => count(array_filter($cards, fn ($c) => self::suitOf($c) === 'D')) * 10,
                'tricks' => (int) (count($cards) / 4) * 15, // كل لطشة = 4 أوراق
                'king_of_hearts' => in_array('KH', $cards, true) ? 75 : 0,
                'queens' => count(array_filter($cards, fn ($c) => self::rankOf($c) === 'Q')) * 25,
                default => 0,
            };
            $scores[(string) $seat] = -$penalty;
        }

        return $scores;
    }

    /**
     * نقاط تسمية التركس — حسب ترتيب خلوص كل لاعب من أوراقه.
     * :param finishOrder: [2, 0, 3, 1] (المقعد 2 خلص أول، 0 ثاني...)
     */
    public static function scoreTrixContract(array $finishOrder): array
    {
        $points = [200, 150, 100, 50];
        $scores = ['0' => 0, '1' => 0, '2' => 0, '3' => 0];

        foreach ($finishOrder as $index => $seat) {
            $scores[(string) $seat] = $points[$index] ?? 0;
        }

        return $scores;
    }

    public static function contractLabel(string $contract): string
    {
        return match ($contract) {
            'diamonds' => 'ديناري',
            'tricks' => 'لطوش',
            'king_of_hearts' => 'شيخ الكبة',
            'queens' => 'بنات',
            'trix' => 'تركس',
            default => $contract,
        };
    }
}
