<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\Models\User;
use App\Notifications\AccountAlreadyExists;
use App\Notifications\RegistrationInvitation;
use Illuminate\Auth\Events\Registered;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
use Illuminate\Validation\Rules;
use Illuminate\View\View;

class RegisteredUserController extends Controller
{
    /**
     * Display the registration view (Phase 1: email collection).
     */
    public function create(): View
    {
        return view('auth.register');
    }

    /**
     * Handle registration request (Phase 2: send magic link).
     * Always returns same "check your inbox" response for both new and existing emails.
     * Rate-limited to prevent enumeration abuse.
     */
    public function request(Request $request): RedirectResponse
    {
        $request->validate([
            'email' => ['required', 'string', 'lowercase', 'email', 'max:255'],
        ]);

        $email = $request->email;
        $user = User::where('email', $email)->first();

        // Generate token (raw token sent in URL, hashed token stored in DB)
        $rawToken = Str::random(64);
        $hashedToken = Hash::make($rawToken);

        DB::table('registration_tokens')->updateOrInsert(
            ['email' => $email],
            ['token' => $hashedToken, 'created_at' => now()]
        );

        // Send appropriate notification
        if ($user) {
            // User already exists - send "account exists" email
            $user->notify(new AccountAlreadyExists());
        } else {
            // New user - send registration invitation with magic link
            // We need to send to the email directly since user doesn't exist yet
            \Illuminate\Support\Facades\Notification::route('mail', $email)
                ->notify(new RegistrationInvitation($email, $rawToken));
        }

        // Always return the same pending page (no indication whether email was found)
        return redirect()->route('register.pending')->with('email', $email);
    }

    /**
     * Show pending registration page after email submission.
     */
    public function pending(Request $request): View
    {
        $email = $request->session()->get('email') ?? session('email');

        return view('auth.register-pending', [
            'email' => $email,
        ]);
    }

    /**
     * Display registration completion form (Phase 3: set password).
     * Validates token before showing form.
     */
    public function complete(Request $request): View
    {
        $email = $request->query('email');
        $token = $request->query('token');

        // Validate email format
        if (!$email || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
            abort(400, 'Invalid registration link.');
        }

        // Check if token exists and is valid
        $tokenRecord = DB::table('registration_tokens')
            ->where('email', $email)
            ->first();

        if (!$tokenRecord) {
            abort(400, 'Invalid or expired registration link.');
        }

        // Verify hashed token
        if (!Hash::check($token, $tokenRecord->token)) {
            abort(400, 'Invalid or expired registration link.');
        }

        // Check token expiry (60 minutes)
        if (now()->diffInMinutes($tokenRecord->created_at) > 60) {
            // Clean up expired token
            DB::table('registration_tokens')->where('email', $email)->delete();
            abort(400, 'Registration link has expired. Please register again.');
        }

        // Store email in session for the completion form
        $request->session()->put('registration_email', $email);
        $request->session()->put('registration_token', $token);

        return view('auth.register-complete', [
            'email' => $email,
        ]);
    }

    /**
     * Finalize registration (Phase 3: create user account).
     * Validates token and password before creating user.
     * Shop name is optional and can be set later when listing items.
     */
    public function finalize(Request $request): RedirectResponse
    {
        // Get email and token from session or form fields (fallback)
        $email = $request->session()->get('registration_email') ?? $request->input('email');
        $token = $request->session()->get('registration_token') ?? $request->input('token');

        // Validate email and token
        if (!$email || !$token) {
            return redirect()->route('register')
                ->with('error', 'Registration session expired. Please try again.');
        }

        // Validate email format
        if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            return redirect()->route('register')
                ->with('error', 'Invalid email address.');
        }

        // Validate the token again
        $tokenRecord = DB::table('registration_tokens')
            ->where('email', $email)
            ->first();

        if (!$tokenRecord || !Hash::check($token, $tokenRecord->token)) {
            return redirect()->route('register')
                ->with('error', 'Invalid registration session. Please try again.');
        }

        // Check token expiry again
        if (now()->diffInMinutes($tokenRecord->created_at) > 60) {
            DB::table('registration_tokens')->where('email', $email)->delete();
            return redirect()->route('register')
                ->with('error', 'Registration link has expired. Please register again.');
        }

        // Validate password only (shop name is now optional)
        $request->validate([
            'password' => ['required', 'confirmed', Rules\Password::defaults()],
        ]);

        // Check if user was somehow created while in registration flow
        if (User::where('email', $email)->exists()) {
            return redirect()->route('login')
                ->with('info', 'This email is already registered. Please sign in.');
        }

        // Create the user with null shop name (can be set later)
        $user = User::create([
            'name' => null,
            'email' => $email,
            'password' => Hash::make($request->password),
        ]);

        // The magic-link token was delivered to this address, so ownership is
        // already proven — mark verified now so the Registered event below
        // doesn't send a redundant verification email.
        $user->markEmailAsVerified();

        // Delete the registration token (one-time use)
        DB::table('registration_tokens')->where('email', $email)->delete();

        // Clear session
        $request->session()->forget(['registration_email', 'registration_token']);

        // Fire registered event and log in
        event(new Registered($user));
        Auth::login($user);

        return redirect(route('dashboard', absolute: false));
    }

    /**
     * Handle an incoming registration request (legacy).
     * Kept for backwards compatibility if needed, otherwise unused.
     *
     * @throws \Illuminate\Validation\ValidationException
     */
    public function store(Request $request): RedirectResponse
    {
        // Redirect to new flow
        return redirect()->route('register');
    }
}
