<?php

namespace App\Http\Controllers;

use App\Models\Country;
use App\Models\GameSession;
use App\Models\GameShot;
use App\Models\Registration;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;

class RegistrationController extends Controller
{
    public function index(Request $request)
    {
        $search = trim($request->input('search', ''));

        $query = Registration::with(['sessions.shots', 'comments']);

        if ($search) {
            $query->where(function ($q) use ($search) {
                $q->where('name', 'like', "%{$search}%")
                ->orWhere('phone', 'like', "%{$search}%")
                ->orWhere('email', 'like', "%{$search}%");
            });
        }

        $registrations = $query->orderBy('id', 'desc')->paginate(20)->withQueryString();

        $data['registrations'] = $registrations;
        $data['search']        = $search;
        $data['countries']     = Country::where('status', 1)->orderBy('title')->get(['id','title','country_flag']);

        return view('registrations', $data);
    }
    public function create()
    {
        return view('registrations.create');
    }

    /*
    |-------------------------------------------------
    | STORE (ONLY USED AFTER OTP FOR NEW USERS)
    |-------------------------------------------------
    */
    public function store(Request $request)
    {
        $request->validate([
            'phone' => 'required',
            'name'  => 'required',
            'email' => 'nullable|email'
        ]);

        $registration = Registration::create([
            'name' => $request->name,
            'email' => $request->email,
            'phone' => $request->phone,
            'total_score' => 0
        ]);

        $session = GameSession::create([
            'registration_id' => $registration->id,
            'play_date' => today(),
            'score' => 0,
        ]);

        return response()->json([
            'status' => 'session_created',
            'registration' => [
                'id' => $registration->id,
                'name' => $registration->name,
                'email' => $registration->email,
                'phone' => $registration->phone,
                'total_score' => 0,
                'today_goals' => [],
                'session_id' => $session->id,
            ]
        ]);
    }

    /*
    |-------------------------------------------------
    | SEND OTP
    |-------------------------------------------------
    */
    public function sendOtp(Request $request)
    {
        $request->validate([
            'phone' => 'required'
        ]);

        $phone = $request->phone;

        $otp = rand(100000, 999999);

        Cache::put("otp_$phone", $otp, now()->addMinutes(2));

        return response()->json([
            'status' => true,
            'otp' => $otp // remove in production
        ]);
    }

    /*
    |-------------------------------------------------
    | VERIFY OTP (CORE LOGIC)
    |-------------------------------------------------
    */
    public function verifyOtp(Request $request)
    {
        $request->validate([
            'phone' => 'required',
            'otp' => 'required'
        ]);

        $phone = $request->phone;

        $cachedOtp = Cache::get("otp_$phone");

        if (!$cachedOtp || $cachedOtp != $request->otp) {
            return response()->json([
                'status' => 'invalid_otp',
                'message' => 'Invalid OTP'
            ], 422);
        }

        Cache::forget("otp_$phone");

        $registration = Registration::where('phone', $phone)->first();

        /*
        | CASE 1: NEW USER
        */
        if (!$registration) {
            return response()->json([
                'status' => 'needs_registration',
                'phone' => $phone
            ]);
        }

        /*
        | CASE 2: ALREADY PLAYED TODAY
        */
        $todaySession = $registration->sessions()
            ->whereDate('play_date', today())
            ->first();
        
        if ($todaySession && $todaySession->isComplete()) {
            return response()->json([
                'status'  => 'blocked',
                'message' => 'This student has already completed today\'s session.',
            ], 409);
        }

        // Session exists but shots not recorded yet — return it
        if ($todaySession) {
            return response()->json([
                'status'       => 'session_created',
                'registration' => [
                    'id'          => $registration->id,
                    'name'        => $registration->name,
                    'email'       => $registration->email,
                    'phone'       => $registration->phone,
                    'total_score' => $registration->total_score,
                    'today_goals' => $todaySession->getShotArray(),
                    'session_id'  => $todaySession->id,
                ]
            ]);
        }
        /*
        | CASE 3: CREATE SESSION IMMEDIATELY
        */
        $session = GameSession::create([
            'registration_id' => $registration->id,
            'play_date' => today(),
            'score' => 0,
        ]);

        return response()->json([
            'status' => 'session_created',
            'registration' => [
                'id' => $registration->id,
                'name' => $registration->name,
                'email' => $registration->email,
                'phone' => $registration->phone,
                'total_score' => $registration->total_score,
                'today_goals' => [],
                'session_id' => $session->id,
            ]
        ]);
    }

    public function resendOtp(Request $request)
    {
        $request->validate([
            'phone' => 'required'
        ]);

        $phone = $request->phone;

        $cooldownKey = 'otp_cooldown_' . $phone;

        if (Cache::has($cooldownKey)) {
            return response()->json([
                'status' => false,
                'message' => 'Please wait before resending OTP'
            ], 429);
        }

        $otp = rand(100000, 999999);

        Cache::put("otp_$phone", $otp, now()->addMinutes(2));
        Cache::put($cooldownKey, true, now()->addSeconds(30));

        return response()->json([
            'status' => true,
            'message' => 'OTP resent successfully',
            'otp' => $otp
        ]);
    }

    public function getRegistrationJson($id)
    {
        $registration = Registration::with('sessions.shots')->findOrFail($id);

        return response()->json([
            'registration' => [
                'id' => $registration->id,
                'name' => $registration->name,
                'email' => $registration->email,
                'phone' => $registration->phone,
                'total_score' => $registration->total_score,
                'today_goals' => optional(
                    $registration->sessions()->whereDate('play_date', today())->first()
                )?->getShotArray()
            ]
        ]);
    }

    public function recordShot(Request $request)
    {
        $request->validate([
            'session_id'  => 'required|exists:game_sessions,id',
            'shot_number' => 'required|integer|in:1,2,3',
            'result'      => 'required|boolean',
        ]);

        $session = GameSession::with('registration')->findOrFail($request->session_id);

        if ($session->shots()->where('shot_number', $request->shot_number)->exists()) {
            return response()->json(['status' => 'error', 'message' => 'Shot already recorded.'], 409);
        }

        GameShot::create([
            'game_session_id' => $session->id,
            'shot_number'     => $request->shot_number,
            'result'          => $request->result,
        ]);

        $sessionScore = $session->calculateScore();
        $session->update(['score' => $sessionScore]);

        $registration = $session->registration;
        $registration->update(['total_score' => $registration->sessions()->sum('score')]);

        return response()->json([
            'status'      => 'ok',
            'total_score' => $registration->fresh()->total_score,
        ]);
    }

    public function recordShots(Request $request)
    {
        $request->validate([
            'session_id' => 'required|exists:game_sessions,id',
            'shots'      => 'required|array|size:3',
            'shots.*'    => 'boolean',
        ]);

        $session = GameSession::with('registration')->findOrFail($request->session_id);

        // Prevent re-recording
        if ($session->isComplete()) {
            return response()->json([
                'status'  => 'error',
                'message' => 'Shots already recorded for this session.'
            ], 409);
        }

        // Store the 3 shots
        foreach ($request->shots as $index => $result) {
            GameShot::create([
                'game_session_id' => $session->id,
                'shot_number'     => $index + 1,
                'result'          => $result,
            ]);
        }

        // Recalculate and update scores
        $sessionScore = $session->calculateScore();
        $session->update(['score' => $sessionScore]);

        $registration = $session->registration;
        $registration->increment('total_score', $sessionScore);

        return response()->json([
            'status'      => 'ok',
            'session_score' => $sessionScore,
            'total_score'   => $registration->fresh()->total_score,
        ]);
    }

    public function correctShot(Request $request)
    {
        $request->validate([
            'session_id'  => 'required|exists:game_sessions,id',
            'shot_number' => 'required|integer|in:1,2,3',
            'result'      => 'required|boolean',
        ]);

        $session = GameSession::with('registration')->findOrFail($request->session_id);

        $shot = $session->shots()->where('shot_number', $request->shot_number)->first();

        if ($shot) {
            $shot->update(['result' => $request->result]);
        } else {
            GameShot::create([
                'game_session_id' => $session->id,
                'shot_number'     => $request->shot_number,
                'result'          => $request->result,
            ]);
        }

        $sessionScore = $session->calculateScore();
        $session->update(['score' => $sessionScore]);

        $registration = $session->registration;
        $registration->update([
            'total_score' => $registration->sessions()->sum('score')
        ]);

        return response()->json([
            'status'      => 'ok',
            'total_score' => $registration->fresh()->total_score,
        ]);
    }

    //Leaderboard
    public function leaderboard()
    {
        $students = Registration::withCount('sessions')
            ->orderByDesc('total_score')
            ->orderBy('name')
            ->paginate(20);
 
        $maxScore = Registration::max('total_score') ?? 0;
        $total    = Registration::count();
 
        $data['students'] = $students;
        $data['maxScore']  = $maxScore;
        $data['total']     = $total;
 
        return view('leaderboard', $data);
    }

    public function history($id)
    {
        $reg = Registration::with(['sessions.shots'])->findOrFail($id);

        $sessions = $reg->sessions
            ->sortByDesc('play_date')
            ->map(fn($s) => [
                'date'  => $s->play_date,
                'score' => $s->score,
                'shots' => $s->shots->sortBy('shot_number')->map(fn($sh) => (bool)$sh->result)->values(),
            ])->values();

        return response()->json(['sessions' => $sessions]);
    }

    public function updateCountry(Request $request, $id)
    {
        $request->validate([
            'country_id' => 'required|exists:countries,id',
        ]);

        $registration = Registration::findOrFail($id);
        $registration->update(['country_id' => $request->country_id]);

        return response()->json([
            'status'       => 'ok',
            'country_id'   => $registration->country_id,
            'country_name' => $registration->country->title,
        ]);
    }

    public function updateStatus(Request $request, $id)
    {
        $request->validate([
            'status' => 'required|in:hot,warm,cold',
        ]);

        $registration = Registration::findOrFail($id);
        $registration->update(['status' => $request->status]);

        return response()->json([
            'status' => 'ok',
            'value'  => $registration->status,
        ]);
    }
    
}