<?php

declare(strict_types=1);

namespace App\Http\Controllers;

use App\Models\ImpersonationToken;
use App\Models\User;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class ImpersonationController extends Controller
{
    /**
     * Start impersonation - generates token and redirects to impersonate
     * Used by admin panel to initiate impersonation via a clickable link
     */
    public function start(Request $request, User $user): RedirectResponse
    {
        // Use the admin guard to check authentication
        $admin = Auth::guard('admin')->user();

        // Verify admin has permission to impersonate
        if (! $admin || ! $admin->is_admin) {
            abort(403, 'Unauthorized');
        }

        // Cannot impersonate other admins
        if ($user->is_admin) {
            abort(403, 'Cannot impersonate administrators');
        }

        // Cannot impersonate inactive users
        if (! $user->is_active) {
            abort(403, 'Cannot impersonate inactive users');
        }

        // Create the impersonation token
        $token = ImpersonationToken::createForUser($admin, $user, $request->ip());

        // Redirect to the impersonation route
        return redirect()->route('impersonate', ['token' => $token->token]);
    }

    public function impersonate(Request $request, string $token): RedirectResponse
    {
        $impersonationToken = ImpersonationToken::findValidToken($token, $request->ip());

        if (! $impersonationToken) {
            return redirect()->route('filament.admin.pages.dashboard')
                ->with('error', 'Invalid or expired impersonation token.');
        }

        // Mark token as used
        $impersonationToken->markAsUsed();

        // Get the target user
        $targetUser = $impersonationToken->targetUser;

        if (! $targetUser || ! $targetUser->is_active) {
            return redirect()->route('filament.admin.pages.dashboard')
                ->with('error', 'User not found or inactive.');
        }

        // Store the admin ID before any session changes
        $adminId = $impersonationToken->admin_id;

        // Clear any previous impersonation session data first
        // This prevents session corruption when impersonating multiple users
        session()->forget('impersonated_by');
        session()->forget('impersonation_token_id');

        // Directly set the user on the web guard without full logout
        // This avoids session invalidation that would affect the admin guard
        Auth::guard('web')->setUser($targetUser);

        // Update the session with the new user's ID for the web guard
        session()->put(Auth::guard('web')->getName(), $targetUser->getAuthIdentifier());

        // Update the password hash in session for AuthenticateSession middleware
        // This prevents the middleware from logging out the user due to hash mismatch
        session()->put('password_hash_web', $targetUser->getAuthPassword());

        // Store impersonation info in session
        session()->put('impersonated_by', $adminId);
        session()->put('impersonation_token_id', $impersonationToken->id);

        // Save the session to persist changes
        session()->save();

        // Redirect to user panel
        return redirect()->route('filament.jabali.pages.dashboard');
    }

    /**
     * Stop impersonation and return to admin panel
     */
    public function stop(): RedirectResponse
    {
        // Clear impersonation session data
        session()->forget('impersonated_by');
        session()->forget('impersonation_token_id');

        // Clear the web guard session data without full logout
        // This preserves the admin session
        session()->forget(Auth::guard('web')->getName());
        session()->forget('password_hash_web');

        // Clear the user from the web guard
        Auth::guard('web')->setUser(null);

        // Save session changes
        session()->save();

        // Redirect back to admin panel
        return redirect()->route('filament.admin.pages.dashboard')
            ->with('success', 'Returned to admin account.');
    }
}
