<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Models\Tournament;
use App\Models\TournamentMatch;
use App\Services\TournamentBracketService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;

class TournamentController extends Controller
{
    public function __construct(private TournamentBracketService $bracket) {}

    public function index()
    {
        $tournaments = Tournament::withCount('participants')->latest()->paginate(15);
        return view('admin.tournaments.index', compact('tournaments'));
    }

    public function show(int $id)
    {
        $tournament = Tournament::withCount('participants')
            ->with(['participants.user', 'creator'])
            ->findOrFail($id);

        $groupData    = [];
        $knockoutData = [];
        if ($tournament->format === 'group_knockout') {
            $groupData = $this->bracket->getGroupStandings($tournament);
        }
        $knockoutData = $this->bracket->getKnockoutBracket($tournament);

        // Players not yet in this tournament — for the add-participant search
        $registeredIds = $tournament->participants->pluck('user_id')->toArray();
        $availableUsers = \App\Models\User::whereNotIn('id', $registeredIds)
            ->where('is_banned', false)
            ->orderByDesc('elo')
            ->get(['id', 'username', 'elo', 'avatar', 'rank']);

        return view('admin.tournaments.show', compact(
            'tournament', 'groupData', 'knockoutData', 'availableUsers'
        ));
    }

    public function edit(int $id)
    {
        $tournament = Tournament::findOrFail($id);
        return view('admin.tournaments.edit', compact('tournament'));
    }

    public function fullUpdate(Request $request, int $id)
    {
        $tournament = Tournament::findOrFail($id);

        $validated = $request->validate([
            'title'                  => ['required', 'string', 'max:100'],
            'description'            => ['nullable', 'string'],
            'prize_1st'              => ['nullable', 'string', 'max:200'],
            'prize_2nd'              => ['nullable', 'string', 'max:200'],
            'prize_3rd'              => ['nullable', 'string', 'max:200'],
            'rules'                  => ['nullable', 'string'],
            'format'                 => ['required', 'in:knockout,group_knockout'],
            'max_players'            => ['required', 'integer', 'min:4', 'max:64'],
            'group_count'            => ['nullable', 'integer', 'min:2', 'max:8'],
            'groups_per_advance'     => ['nullable', 'integer', 'min:1', 'max:4'],
            'bo_group'               => ['nullable', 'integer', 'min:1', 'max:5'],
            'bo_knockout'            => ['nullable', 'integer', 'min:1', 'max:5'],
            'bo_final'               => ['nullable', 'integer', 'min:1', 'max:5'],
            'ban_group'              => ['nullable', 'integer', 'min:0', 'max:10'],
            'ban_knockout'           => ['nullable', 'integer', 'min:0', 'max:10'],
            'ban_final'              => ['nullable', 'integer', 'min:0', 'max:10'],
            'tiebreak_mode'          => ['nullable', 'in:aggregate,golden_goal'],
            'status'                 => ['required', 'in:draft,registration,in_progress,completed,cancelled'],
            'registration_opens_at'  => ['nullable', 'date'],
            'registration_closes_at' => ['nullable', 'date'],
            'starts_at'              => ['nullable', 'date'],
            'thumbnail'              => ['nullable', 'image', 'mimes:jpg,jpeg,png,webp', 'max:2048'],
        ]);

        $validated['bo_config'] = [
            'group'   => (int) ($validated['bo_group']   ?? 1),
            'knockout'=> (int) ($validated['bo_knockout'] ?? 1),
            'final'   => (int) ($validated['bo_final']   ?? 1),
        ];
        $validated['ban_config'] = [
            'group'   => (int) ($validated['ban_group']   ?? 0),
            'knockout'=> (int) ($validated['ban_knockout'] ?? 0),
            'final'   => (int) ($validated['ban_final']   ?? 0),
        ];
        unset($validated['bo_group'], $validated['bo_knockout'], $validated['bo_final'],
              $validated['ban_group'], $validated['ban_knockout'], $validated['ban_final']);

        $validated['tiebreak_mode'] = $request->input('tiebreak_mode', 'aggregate');

        if ($request->hasFile('thumbnail')) {
            // Delete old thumbnail if exists
            if ($tournament->thumbnail) {
                Storage::disk('public')->delete($tournament->thumbnail);
            }
            $validated['thumbnail'] = $request->file('thumbnail')->store('tournaments', 'public');
        } else {
            unset($validated['thumbnail']);
        }

        $tournament->update($validated);

        return redirect()->route('admin.tournaments.show', $id)
            ->with('success', 'Turnamen berhasil diperbarui!');
    }

    public function destroy(int $id)
    {
        $tournament = Tournament::findOrFail($id);

        // Cascade: clear FK refs first
        DB::transaction(function () use ($tournament) {
            TournamentMatch::where('tournament_id', $tournament->id)
                ->update(['next_match_id' => null]);
            TournamentMatch::where('tournament_id', $tournament->id)->delete();
            $tournament->participants()->delete();
            $tournament->delete();
        });

        return redirect()->route('admin.tournaments')
            ->with('success', 'Turnamen "' . $tournament->title . '" berhasil dihapus.');
    }

    public function store(Request $request)
    {
        $validated = $request->validate([
            'title'                  => ['required', 'string', 'max:100'],
            'description'            => ['nullable', 'string'],
            'prize_1st'              => ['nullable', 'string', 'max:200'],
            'prize_2nd'              => ['nullable', 'string', 'max:200'],
            'prize_3rd'              => ['nullable', 'string', 'max:200'],
            'rules'                  => ['nullable', 'string'],
            'format'                 => ['required', 'in:knockout,group_knockout'],
            'max_players'            => ['required', 'integer', 'min:4', 'max:64'],
            'group_count'            => ['required_if:format,group_knockout', 'integer', 'min:2', 'max:8'],
            'groups_per_advance'     => ['required_if:format,group_knockout', 'integer', 'min:1', 'max:4'],
            'bo_group'               => ['nullable', 'integer', 'min:1', 'max:5'],
            'bo_knockout'            => ['nullable', 'integer', 'min:1', 'max:5'],
            'bo_final'               => ['nullable', 'integer', 'min:1', 'max:5'],
            'ban_group'              => ['nullable', 'integer', 'min:0', 'max:10'],
            'ban_knockout'           => ['nullable', 'integer', 'min:0', 'max:10'],
            'ban_final'              => ['nullable', 'integer', 'min:0', 'max:10'],
            'tiebreak_mode'          => ['nullable', 'in:aggregate,golden_goal'],
            'registration_opens_at'  => ['nullable', 'date'],
            'registration_closes_at' => ['nullable', 'date'],
            'starts_at'              => ['nullable', 'date'],
            'thumbnail'              => ['nullable', 'image', 'mimes:jpg,jpeg,png,webp', 'max:2048'],
        ]);

        if ($request->hasFile('thumbnail')) {
            $validated['thumbnail'] = $request->file('thumbnail')->store('tournaments', 'public');
        }

        $validated['bo_config'] = [
            'group'   => (int) ($validated['bo_group']   ?? 1),
            'knockout'=> (int) ($validated['bo_knockout'] ?? 1),
            'final'   => (int) ($validated['bo_final']   ?? 1),
        ];
        $validated['ban_config'] = [
            'group'   => (int) ($validated['ban_group']   ?? 0),
            'knockout'=> (int) ($validated['ban_knockout'] ?? 0),
            'final'   => (int) ($validated['ban_final']   ?? 0),
        ];
        unset($validated['bo_group'], $validated['bo_knockout'], $validated['bo_final'],
              $validated['ban_group'], $validated['ban_knockout'], $validated['ban_final']);

        $validated['tiebreak_mode'] = $request->input('tiebreak_mode', 'aggregate');

        Tournament::create([
            ...$validated,
            'created_by'    => auth()->id(),
            'status'        => 'draft',
            'current_phase' => 'group',
        ]);

        return redirect()->route('admin.tournaments')->with('success', 'Turnamen berhasil dibuat!');
    }

    public function update(Request $request, int $id)
    {
        $tournament = Tournament::findOrFail($id);

        $validated = $request->validate([
            'status' => ['required', 'in:draft,registration,in_progress,completed,cancelled'],
        ]);

        $tournament->update($validated);
        return back()->with('success', 'Status turnamen diperbarui.');
    }

    /**
     * Save manual knockout draw (seed order from roulette) and regenerate bracket.
     * Expects JSON: { "seeds": [uid1, uid2, uid3, ...] }  (ordered seed 1 → N)
     */
    public function knockoutDraw(Request $request, int $id)
    {
        $tournament = Tournament::findOrFail($id);
        $seeds = $request->validate(['seeds' => ['required', 'array']])['seeds'];

        DB::transaction(function () use ($tournament, $seeds) {
            // Assign seeds based on draw order
            foreach ($seeds as $index => $userId) {
                \App\Models\TournamentParticipant::where('tournament_id', $tournament->id)
                    ->where('user_id', $userId)
                    ->update(['seed' => $index + 1]);
            }

            // Clear old matches
            \App\Models\TournamentMatch::where('tournament_id', $tournament->id)
                ->update(['next_match_id' => null, 'series_parent_id' => null]);
            \App\Models\TournamentMatch::where('tournament_id', $tournament->id)->delete();

            // Regenerate bracket with new seed order
            $participants = $tournament->participants()
                ->with('user')
                ->orderBy('seed')
                ->get();

            // Use seeded player IDs in order
            $playerIds = $participants->pluck('user_id')->toArray();

            // Generate knockout bracket (service will use the seed order as-is)
            app(\App\Services\TournamentBracketService::class)
                ->generateKnockoutFromSeeds($tournament, $playerIds);

            $tournament->update(['current_phase' => 'knockout']);
        });

        return response()->json(['ok' => true]);
    }

    /**
     * Show bracket management page for admin.
     */
    public function bracket(int $id)
    {
        $tournament = Tournament::with(['participants.user'])->findOrFail($id);

        $groupData    = [];
        $knockoutData = [];

        if ($tournament->format === 'group_knockout') {
            $groupData = $this->bracket->getGroupStandings($tournament);
        }
        $knockoutData = $this->bracket->getKnockoutBracket($tournament);

        return view('admin.tournaments.bracket', compact('tournament', 'groupData', 'knockoutData'));
    }

    /**
     * Generate / regenerate bracket.
     */
    public function generateBracket(int $id)
    {
        $tournament = Tournament::findOrFail($id);
        abort_if($tournament->participants()->count() < 2, 422, 'Minimal 2 peserta dibutuhkan.');

        $this->bracket->generate($tournament);

        return redirect()->route('admin.tournament.bracket', $id)
            ->with('success', 'Bracket berhasil dibuat!');
    }

    /**
     * Advance group → knockout.
     */
    public function advanceKnockout(int $id)
    {
        $tournament = Tournament::findOrFail($id);
        $ok = $this->bracket->advanceToKnockout($tournament);

        if (!$ok) {
            return back()->with('error', 'Masih ada match group yang belum selesai.');
        }

        return redirect()->route('admin.tournament.bracket', $id)
            ->with('success', 'Fase Knockout berhasil dimulai!');
    }

    /**
     * Check if tiebreaker matches need to be created and create them.
     */
    public function checkTiebreakers(int $id)
    {
        $tournament = Tournament::findOrFail($id);
        $created    = $this->bracket->createTiebreakerMatches($tournament);

        if ($created > 0) {
            return redirect()->route('admin.tournament.bracket', $id)
                ->with('success', $created . ' pertandingan Golden Goal tiebreaker berhasil dibuat!');
        }

        return redirect()->route('admin.tournament.bracket', $id)
            ->with('success', 'Tidak ada tiebreaker yang dibutuhkan. Siap lanjut ke Knockout!');
    }

    /**
     * Save manual group assignments from wheel draw.
     * Expects JSON: { groups: { "A": [uid,...], "B": [uid,...], ... } }
     */
    public function assignGroups(Request $request, int $id)
    {
        $tournament = Tournament::findOrFail($id);
        $groups     = $request->validate(['groups' => ['required','array']])['groups'];

        DB::transaction(function () use ($tournament, $groups) {
            // Remove existing group matches only
            \App\Models\TournamentMatch::where('tournament_id', $tournament->id)
                ->where('phase', 'group')
                ->update(['next_match_id' => null, 'series_parent_id' => null]);
            \App\Models\TournamentMatch::where('tournament_id', $tournament->id)
                ->where('phase', 'group')
                ->delete();

            $matchNumber = 1;
            $bo          = $tournament->getBoForPhase('group');

            foreach ($groups as $groupLabel => $members) {
                $members = array_values(array_filter($members));
                for ($a = 0; $a < count($members); $a++) {
                    for ($b = $a + 1; $b < count($members); $b++) {
                        // Create leg 1 (root)
                        $root = \App\Models\TournamentMatch::create([
                            'tournament_id' => $tournament->id,
                            'round'         => 1,
                            'match_number'  => $matchNumber++,
                            'leg_number'    => 1,
                            'phase'         => 'group',
                            'group_name'    => strtoupper($groupLabel),
                            'player1_id'    => $members[$a],
                            'player2_id'    => $members[$b],
                            'status'        => 'pending',
                        ]);

                        // Create additional legs for BO2+
                        for ($leg = 2; $leg <= $bo; $leg++) {
                            \App\Models\TournamentMatch::create([
                                'tournament_id'    => $tournament->id,
                                'round'            => 1,
                                'match_number'     => $matchNumber++,
                                'leg_number'       => $leg,
                                'series_parent_id' => $root->id,
                                'phase'            => 'group',
                                'group_name'       => strtoupper($groupLabel),
                                'player1_id'       => $members[$a],
                                'player2_id'       => $members[$b],
                                'status'           => 'pending',
                            ]);
                        }
                    }
                }
            }

            $tournament->update(['current_phase' => 'group']);
        });

        return response()->json(['ok' => true]);
    }

    /**
     * Add a player manually to a tournament (admin only).
     */
    public function addParticipant(Request $request, int $id)
    {
        $tournament = Tournament::withCount('participants')->findOrFail($id);

        $request->validate([
            'user_id' => ['required', 'integer', 'exists:users,id'],
        ]);

        $userId = (int) $request->user_id;

        if ($tournament->participants_count >= $tournament->max_players) {
            return back()->with('error', 'Turnamen sudah penuh (' . $tournament->max_players . ' pemain).');
        }

        $exists = \App\Models\TournamentParticipant::where('tournament_id', $id)
            ->where('user_id', $userId)->exists();

        if ($exists) {
            return back()->with('error', 'Pemain sudah terdaftar di turnamen ini.');
        }

        \App\Models\TournamentParticipant::create([
            'tournament_id' => $id,
            'user_id'       => $userId,
            'status'        => 'confirmed',
        ]);

        $user = \App\Models\User::find($userId);
        return back()->with('success', $user->username . ' berhasil ditambahkan ke turnamen.');
    }

    /**
     * Remove a participant from a tournament (admin only).
     */
    public function removeParticipant(int $id, int $uid)
    {
        $participant = \App\Models\TournamentParticipant::where('tournament_id', $id)
            ->where('user_id', $uid)->firstOrFail();

        $username = $participant->user->username;
        $participant->delete();

        return back()->with('success', $username . ' berhasil dihapus dari turnamen.');
    }

    public function submitScore(Request $request, int $tournamentId, int $matchId)
    {
        $request->validate([
            'score1' => ['required', 'integer', 'min:0', 'max:99'],
            'score2' => ['required', 'integer', 'min:0', 'max:99'],
        ]);

        $match = TournamentMatch::where('tournament_id', $tournamentId)->findOrFail($matchId);

        try {
            $this->bracket->submitScore($match, (int) $request->score1, (int) $request->score2);
        } catch (\InvalidArgumentException $e) {
            return back()->with('error', $e->getMessage());
        }

        return back()->with('success', 'Skor berhasil disimpan!');
    }
}
