<?php

namespace App\Http\Controllers\Api;

use App\Events\TrixUpdated;
use App\Http\Controllers\Controller;
use App\Models\PlatformSetting;
use App\Models\TrixGame;
use App\Models\TrixHandHistory;
use App\Models\User;
use App\Models\WalletTransaction;
use App\Services\TrixEngine;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Illuminate\Validation\Rule;

class TrixGameController extends Controller
{
    protected const JOIN_TIMEOUT_MINUTES = 20;
    protected const TOTAL_KINGDOMS = 4;

    // ==============================================================
    // إنشاء لعبة جديدة
    // ==============================================================

    public function store(Request $request)
    {
        $data = $request->validate([
            'bet_amount_per_player' => 'required|numeric|min:100',
        ]);

        $user = $request->user();
        $amount = (float) $data['bet_amount_per_player'];

        if ($user->wallet->balance < $amount) {
            return response()->json(['message' => 'رصيدك غير كافٍ لهذا الرهان'], 400);
        }

        $game = DB::transaction(function () use ($user, $amount) {
            $user->wallet()->decrement('balance', $amount);

            WalletTransaction::create([
                'transaction_id' => (string) Str::uuid(),
                'user_id' => $user->id,
                'type' => 'game_bet',
                'amount' => $amount,
                'status' => 'completed',
            ]);

            return TrixGame::create([
                'seat0_user_id' => $user->id,
                'bet_amount_per_player' => $amount,
                'commission_percent' => PlatformSetting::get('commission_percent', 10),
                'status' => 'waiting',
                'expires_at' => now()->addMinutes(self::JOIN_TIMEOUT_MINUTES),
                'scores' => ['0' => 0, '1' => 0, '2' => 0, '3' => 0],
            ]);
        });

        return response()->json([
            'game' => $this->formatGame($game, $user->id),
            'invite_url' => config('app.frontend_url') . '/games/trix/' . $game->uuid,
        ], 201);
    }

    public function show(Request $request, string $uuid)
    {
        $game = TrixGame::with(['seat0', 'seat1', 'seat2', 'seat3'])->where('uuid', $uuid)->firstOrFail();
        return response()->json($this->formatGame($game, $request->user()?->id));
    }

    // ==============================================================
    // الانضمام
    // ==============================================================

    public function join(Request $request, string $uuid)
    {
        $user = $request->user();

        $game = DB::transaction(function () use ($user, $uuid) {
            $game = TrixGame::where('uuid', $uuid)->lockForUpdate()->firstOrFail();

            if ($game->status !== 'waiting') {
                abort(400, 'هذه اللعبة لم تعد متاحة للانضمام');
            }
            if (in_array($user->id, array_filter($game->seatUserIds()), true)) {
                abort(400, 'أنت منضم أصلاً لهذه اللعبة');
            }
            if ($game->expires_at && $game->expires_at->isPast()) {
                abort(400, 'انتهت مهلة الانضمام لهذه اللعبة');
            }
            if ($user->wallet->balance < $game->bet_amount_per_player) {
                abort(400, 'رصيدك غير كافٍ للانضمام لهذا الرهان');
            }

            $nextSeat = match (true) {
                $game->seat2_user_id === null => 2,
                $game->seat1_user_id === null => 1,
                $game->seat3_user_id === null => 3,
                default => abort(400, 'اللعبة مكتملة بالفعل'),
            };

            $user->wallet()->decrement('balance', $game->bet_amount_per_player);

            WalletTransaction::create([
                'transaction_id' => (string) Str::uuid(),
                'user_id' => $user->id,
                'type' => 'game_bet',
                'amount' => $game->bet_amount_per_player,
                'status' => 'completed',
            ]);

            $game->update(["seat{$nextSeat}_user_id" => $user->id]);
            $game->refresh();

            if ($game->isFull()) {
                $this->startNewKingdomIfNeeded($game, true);
                $this->startNewHand($game);
                $game->update(['status' => 'in_progress', 'expires_at' => null]);
            }

            return $game->fresh(['seat0', 'seat1', 'seat2', 'seat3']);
        });

        broadcast(new TrixUpdated($game->uuid))->toOthers();

        return response()->json($this->formatGame($game, $user->id));
    }

    // ==============================================================
    // اختيار التسمية (الملك بس يقدر يستخدمها)
    // ==============================================================

    public function chooseContract(Request $request, string $uuid)
    {
        $data = $request->validate([
            'contract' => ['required', Rule::in(TrixEngine::CONTRACTS)],
        ]);

        $user = $request->user();

        DB::transaction(function () use ($user, $uuid, $data) {
            $game = TrixGame::where('uuid', $uuid)->lockForUpdate()->firstOrFail();

            $seat = $game->seatOf($user->id);
            if ($seat === null || $seat !== $game->king_seat) {
                abort(403, 'أنت مش الملك حالياً — بس الملك يقدر يختار التسمية');
            }
            if ($game->phase !== 'choosing_contract') {
                abort(400, 'مو وقت اختيار التسمية حالياً');
            }

            $played = $game->contracts_played_this_kingdom ?? [];
            if (in_array($data['contract'], $played, true)) {
                abort(400, 'هذه التسمية اتلعبت أصلاً هالمملكة');
            }

            $game->current_contract = $data['contract'];
            $game->phase = 'playing';

            if ($data['contract'] === 'trix') {
                $game->trix_layout = ['H' => null, 'D' => null, 'S' => null, 'C' => null];
                $game->trix_finish_order = [];
            } else {
                $game->current_trick = ['leader_seat' => null, 'cards' => []];
                $game->lead_suit = null;
                $game->captured_cards_this_hand = ['0' => [], '1' => [], '2' => [], '3' => []];
            }

            // الملك يبلش أول لطشة/أول محاولة ترصيف بكل تسمية يختارها
            $game->current_turn_seat = $game->king_seat;
            $game->save();
        });

        broadcast(new TrixUpdated($uuid));

        $game = TrixGame::with(['seat0', 'seat1', 'seat2', 'seat3'])->where('uuid', $uuid)->first();
        return response()->json($this->formatGame($game, $user->id));
    }

    // ==============================================================
    // لعب ورقة (التسميات الأربعة القائمة على اللطش)
    // ==============================================================

    public function playCard(Request $request, string $uuid)
    {
        $data = $request->validate(['card' => 'required|string']);
        $user = $request->user();

        DB::transaction(function () use ($user, $uuid, $data) {
            $game = TrixGame::where('uuid', $uuid)->lockForUpdate()->firstOrFail();

            $seat = $game->seatOf($user->id);
            if ($seat === null) abort(403, 'أنت لست طرفاً بهذه اللعبة');
            if ($game->phase !== 'playing' || $game->current_contract === 'trix') {
                abort(400, 'مو وقت لعب ورقة اعتيادية حالياً');
            }
            if ($game->current_turn_seat !== $seat) abort(400, 'مو دورك تلعب');

            $hands = $game->hands;
            $playerHand = $hands[(string) $seat] ?? [];

            if (!TrixEngine::isValidTrickPlay($playerHand, $data['card'], $game->lead_suit)) {
                abort(400, 'حركة غير قانونية — لازم تتبع نوع الورقة القائدة لو معك منها');
            }

            $hands[(string) $seat] = array_values(array_diff($playerHand, [$data['card']]));
            $game->hands = $hands;

            $trick = $game->current_trick;
            $trick['cards'][(string) $seat] = $data['card'];
            if ($game->lead_suit === null) {
                $game->lead_suit = TrixEngine::suitOf($data['card']);
                $trick['leader_seat'] = $seat;
            }
            $game->current_trick = $trick;

            if (count($trick['cards']) < 4) {
                $game->current_turn_seat = ($seat + 1) % 4;
                $game->save();
                return;
            }

            // ✅ اكتملت اللطشة
            $winnerSeat = TrixEngine::resolveTrick($trick['cards'], $game->lead_suit);

            $captured = $game->captured_cards_this_hand;
            $captured[(string) $winnerSeat] = array_merge(
                $captured[(string) $winnerSeat] ?? [],
                array_values($trick['cards'])
            );
            $game->captured_cards_this_hand = $captured;

            $game->current_trick = ['leader_seat' => $winnerSeat, 'cards' => []];
            $game->current_turn_seat = $winnerSeat;
            $game->lead_suit = null;

            // ------------------------------------------------------------
            // 🏁 إنهاء مبكر: بمجرد ما نتيجة التسمية تتحدد رياضياً بالكامل،
            // ما في داعي نكمل باقي اللطشات — أوراق اليد المتبقية بترمى
            // (التوزيعة الجاية أصلاً بتوزّع أوراق جديدة من الصفر)
            // ------------------------------------------------------------
            $earlyEnd = match ($game->current_contract) {
                'king_of_hearts' => in_array('KH', array_merge(...array_values($captured)), true),
                'diamonds' => array_sum(array_map(
                    fn ($cards) => count(array_filter($cards, fn ($c) => TrixEngine::suitOf($c) === 'D')),
                    $captured
                )) >= 13,
                'queens' => array_sum(array_map(
                    fn ($cards) => count(array_filter($cards, fn ($c) => TrixEngine::rankOf($c) === 'Q')),
                    $captured
                )) >= 4,
                default => false,
            };

            $handOver = $earlyEnd || array_sum(array_map('count', $hands)) === 0;

            if (!$handOver) {
                $game->save();
                return;
            }

            $this->finishHand($game, TrixEngine::scoreTrickContract($game->current_contract, $captured));
        });

        broadcast(new TrixUpdated($uuid));

        $game = TrixGame::with(['seat0', 'seat1', 'seat2', 'seat3'])->where('uuid', $uuid)->first();
        return response()->json($this->formatGame($game, $user->id));
    }

    // ==============================================================
    // ترصيف ورقة أو تمرير (تسمية التركس فقط)
    // ==============================================================

    public function playTrixCard(Request $request, string $uuid)
    {
        $data = $request->validate([
            'card' => 'nullable|string', // فاضي = تمرير (باس)
        ]);

        $user = $request->user();

        DB::transaction(function () use ($user, $uuid, $data) {
            $game = TrixGame::where('uuid', $uuid)->lockForUpdate()->firstOrFail();

            $seat = $game->seatOf($user->id);
            if ($seat === null) abort(403, 'أنت لست طرفاً بهذه اللعبة');
            if ($game->phase !== 'playing' || $game->current_contract !== 'trix') {
                abort(400, 'مو وقت ترصيف حالياً');
            }
            if ($game->current_turn_seat !== $seat) abort(400, 'مو دورك');

            $hands = $game->hands;
            $playerHand = $hands[(string) $seat] ?? [];
            $layout = $game->trix_layout;

            if (empty($data['card'])) {
                // باس — بس لو فعلاً ما عنده ورقة قابلة للترصيف
                if (TrixEngine::hasAnyValidTrixPlay($layout, $playerHand)) {
                    abort(400, 'عندك ورقة قابلة للترصيف، ما تقدر تمرّر');
                }
            } else {
                if (!in_array($data['card'], $playerHand, true)) {
                    abort(400, 'الورقة مش معك');
                }
                if (!TrixEngine::isValidTrixPlacement($layout, $data['card'])) {
                    abort(400, 'حركة غير قانونية — الورقة مش قابلة للترصيف حالياً');
                }

                $hands[(string) $seat] = array_values(array_diff($playerHand, [$data['card']]));
                $game->hands = $hands;
                $game->trix_layout = TrixEngine::applyTrixPlacement($layout, $data['card']);

                if (empty($hands[(string) $seat])) {
                    $finishOrder = $game->trix_finish_order ?? [];
                    $finishOrder[] = $seat;
                    $game->trix_finish_order = $finishOrder;
                }
            }

            // الدور التالي — نتخطى أي مقعد خلّص أوراقه أصلاً
            $finishOrder = $game->trix_finish_order ?? [];
            $next = $seat;
            for ($i = 0; $i < 4; $i++) {
                $next = ($next + 1) % 4;
                if (!in_array($next, $finishOrder, true)) {
                    break;
                }
            }
            $game->current_turn_seat = $next;

            $allFinished = count($game->trix_finish_order ?? []) === 4;

            if (!$allFinished) {
                $game->save();
                return;
            }

            $this->finishHand($game, TrixEngine::scoreTrixContract($game->trix_finish_order));
        });

        broadcast(new TrixUpdated($uuid));

        $game = TrixGame::with(['seat0', 'seat1', 'seat2', 'seat3'])->where('uuid', $uuid)->first();
        return response()->json($this->formatGame($game, $user->id));
    }

    // ==============================================================
    // دوال داخلية
    // ==============================================================

    protected function startNewKingdomIfNeeded(TrixGame $game, bool $isFirstEver = false): void
    {
        if ($isFirstEver) {
            $game->kingdom_number = 1;
            $game->contracts_played_this_kingdom = [];
            // الملك الأول يتحدد بسبعة الكبة بأول توزيعة فعلية (تصير بـ startNewHand)
            $game->king_seat = null;
        }
    }

    protected function startNewHand(TrixGame $game): void
    {
        $hands = TrixEngine::dealFresh();
        $game->hands = $hands;

        if ($game->king_seat === null) {
            // أول يد بالماتش كامل — نحدد الملك بسبعة الكبة
            $game->king_seat = TrixEngine::findSevenOfHeartsSeat($hands);
        }

        $game->phase = 'choosing_contract';
        $game->current_contract = null;
        $game->current_turn_seat = null;
        $game->current_trick = null;
        $game->lead_suit = null;
        $game->captured_cards_this_hand = null;
        $game->trix_layout = null;
        $game->trix_finish_order = null;
        $game->save();
    }

    /**
     * حسم تسمية واحدة خلصت (سواء لطش أو تركس)، تحديث النقاط، وإما تسمية جديدة
     * نفس المملكة أو انتقال المملكة أو نهاية الماتش بالكامل.
     */
    protected function finishHand(TrixGame $game, array $handScores): void
    {
        $scores = $game->scores;
        foreach ($handScores as $seat => $delta) {
            $scores[(string) $seat] = (int) $scores[(string) $seat] + (int) $delta;
        }
        $game->scores = $scores;

        TrixHandHistory::create([
            'game_id' => $game->id,
            'kingdom_number' => $game->kingdom_number,
            'contract' => $game->current_contract,
            'hand_scores' => $handScores,
        ]);

        $played = $game->contracts_played_this_kingdom ?? [];
        $played[] = $game->current_contract;
        $game->contracts_played_this_kingdom = $played;

        $kingdomComplete = count($played) >= 5;

        if (!$kingdomComplete) {
            // نفس المملكة، الملك يختار تسمية جديدة من الباقي
            $game->phase = 'choosing_contract';
            $game->current_contract = null;
            $game->save();
            $this->startNewHand($game->fresh());
            return;
        }

        // ✅ خلصت المملكة — هل خلص الماتش (4 ممالك) وفيه فايز واضح؟
        if ($game->kingdom_number >= self::TOTAL_KINGDOMS) {
            $teamAScore = (int) $scores['0'] + (int) $scores['2'];
            $teamBScore = (int) $scores['1'] + (int) $scores['3'];

            if ($teamAScore !== $teamBScore) {
                $this->finalizeMatch($game, $teamAScore > $teamBScore ? 'A' : 'B');
                return;
            }
            // تعادل — مملكة إضافية (نفس منطق التمديد تحت)
        }

        // مملكة جديدة — تنتقل لليمين (المقعد التالي)
        $game->kingdom_number += 1;
        $game->king_seat = ($game->king_seat + 1) % 4;
        $game->contracts_played_this_kingdom = [];
        $game->phase = 'choosing_contract';
        $game->current_contract = null;
        $game->save();

        $this->startNewHand($game->fresh());
    }

    protected function finalizeMatch(TrixGame $game, string $winningTeam): void
    {
        $pot = $game->potAmount();
        $commission = round($pot * ((float) $game->commission_percent / 100), 2);
        $payoutTotal = $pot - $commission;
        $payoutEach = round($payoutTotal / 2, 2);

        $winnerSeats = $winningTeam === 'A' ? [0, 2] : [1, 3];
        $seatUserIds = $game->seatUserIds();

        foreach ($winnerSeats as $seat) {
            $winnerUser = User::find($seatUserIds[$seat]);
            $winnerUser->wallet()->increment('balance', $payoutEach);

            WalletTransaction::create([
                'transaction_id' => (string) Str::uuid(),
                'user_id' => $winnerUser->id,
                'type' => 'game_win',
                'amount' => $payoutEach,
                'status' => 'completed',
            ]);
        }

        $game->status = 'completed';
        $game->winner_team = $winningTeam;
        $game->commission_amount = $commission;
        $game->payout_per_winner = $payoutEach;
        $game->save();
    }

    protected function formatGame(TrixGame $game, ?int $viewerId): array
    {
        $viewerSeat = $viewerId ? $game->seatOf($viewerId) : null;

        $players = [];
        foreach ([0, 1, 2, 3] as $seat) {
            $relation = $game->{"seat{$seat}"};
            $players[$seat] = $relation ? [
                'id' => $relation->id,
                'username' => $relation->username,
                'team' => $game->teamOf($seat),
            ] : null;
        }

        return [
            'uuid' => $game->uuid,
            'status' => $game->status,
            'phase' => $game->phase,
            'bet_amount_per_player' => (float) $game->bet_amount_per_player,
            'pot_amount' => $game->potAmount(),
            'commission_percent' => (float) $game->commission_percent,
            'players' => $players,
            'viewer_seat' => $viewerSeat,
            'king_seat' => $game->king_seat,
            'kingdom_number' => $game->kingdom_number,
            'contracts_played_this_kingdom' => $game->contracts_played_this_kingdom ?? [],
            'contracts_remaining' => array_values(array_diff(
                TrixEngine::CONTRACTS,
                $game->contracts_played_this_kingdom ?? []
            )),
            'current_contract' => $game->current_contract,
            'current_turn_seat' => $game->current_turn_seat,
            'current_trick' => $game->current_trick,
            'lead_suit' => $game->lead_suit,
            'trix_layout' => $game->trix_layout,
            'trix_finish_order' => $game->trix_finish_order,
            'scores' => $game->scores,
            'team_scores' => [
                'A' => (int) ($game->scores['0'] ?? 0) + (int) ($game->scores['2'] ?? 0),
                'B' => (int) ($game->scores['1'] ?? 0) + (int) ($game->scores['3'] ?? 0),
            ],
            'winner_team' => $game->winner_team,
            'payout_per_winner' => $game->payout_per_winner !== null ? (float) $game->payout_per_winner : null,
            'my_hand' => $viewerSeat !== null ? ($game->hands[(string) $viewerSeat] ?? []) : [],
            'my_can_pass_trix' => $viewerSeat !== null && $game->current_contract === 'trix' && $game->trix_layout
                ? !TrixEngine::hasAnyValidTrixPlay($game->trix_layout, $game->hands[(string) $viewerSeat] ?? [])
                : false,
        ];
    }
}