<?php

namespace App\Http\Requests;

use App\Events\ProfileVerified;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Log;
use Illuminate\Validation\Validator;

class ProfileEmailVerificationRequest extends FormRequest
{
    public $profileModel;

    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
public function authorize()
    {
        $type = $this->route('type');
        $profileId = $this->route('id');
        $modelClass = 'App\\Models\\' . \Illuminate\Support\Str::studly($type);

        if (!class_exists($modelClass)) {
            Log::warning("Authorization failed: Model class does not exist - {$modelClass}");
            return false;
        }

        $profileModel = $modelClass::find($profileId);
        if (!$profileModel) {
            Log::warning("Authorization failed: Profile model not found - {$modelClass} with ID {$profileId}");
            return false;
        }

        // Check all guards to find authenticated user
        $loggedInUser = $this->user(); // Try default web guard first

        // If not on web guard, check other guards
        if (!$loggedInUser) {
            $guards = ['organization', 'bank', 'admin'];
            foreach ($guards as $guard) {
                $loggedInUser = auth()->guard($guard)->user();
                if ($loggedInUser) {
                    Log::info("Found authenticated user on '{$guard}' guard", [
                        'user_id' => $loggedInUser->id,
                        'user_type' => get_class($loggedInUser),
                    ]);
                    break;
                }
            }
        }

        if (!$loggedInUser) {
            Log::warning("Authorization failed: No authenticated user on any guard.");
            return false;
        }

        $isAssociated = false; // Flag to track if user is associated with the profile
        $emailToVerify = null;

        // --- Check Association and Get Email ---

        // First check: Is the logged-in entity the same as the profile being verified?
        if (get_class($loggedInUser) === get_class($profileModel) && $loggedInUser->id === $profileModel->id) {
            // User is verifying their own profile (e.g., Organization verifying Organization email)
            $isAssociated = true;
            $emailToVerify = method_exists($profileModel, 'getEmailForVerification')
                ? $profileModel->getEmailForVerification()
                : $profileModel->email;
            Log::info("Authorization: Logged-in entity is verifying own email", [
                'entity_type' => get_class($profileModel),
                'entity_id' => $profileModel->id,
            ]);
        } elseif ($profileModel instanceof \App\Models\User) {
            // Case 1: Profile is a User model (and logged-in user is different)
            if ($loggedInUser instanceof \App\Models\User && $profileModel->id === $loggedInUser->id) {
                $isAssociated = true;
                $emailToVerify = $loggedInUser->getEmailForVerification();
            } else {
                Log::warning("Authorization failed: User ID mismatch. Profile ID: {$profileModel->id}, Logged-in User ID: {$loggedInUser->id}");
            }
        } else {
            // Case 2: Profile is Organization, Bank, Admin, etc. and logged-in user is a User
            if ($loggedInUser instanceof \App\Models\User) {
                // Check 'users' relationship first
                if (method_exists($profileModel, 'users')) {
                    if ($profileModel->users()->whereKey($loggedInUser->id)->exists()) {
                        $isAssociated = true;
                    }
                }
                // If not associated via 'users', check 'managers' relationship
                elseif (method_exists($profileModel, 'managers')) {
                    if ($profileModel->managers()->whereKey($loggedInUser->id)->exists()) {
                        $isAssociated = true;
                    }
                }

                if ($isAssociated) {
                    // Use the profileModel's email for verification
                    $emailToVerify = method_exists($profileModel, 'getEmailForVerification')
                        ? $profileModel->getEmailForVerification()
                        : $profileModel->email;
                } else {
                    Log::warning("Authorization failed: User ID {$loggedInUser->id} not associated with " . class_basename($profileModel) . " ID {$profileModel->id} via users() or managers().");
                }
            } else {
                Log::warning("Authorization failed: Logged-in entity is not a User and doesn't match profile", [
                    'logged_in_type' => get_class($loggedInUser),
                    'logged_in_id' => $loggedInUser->id,
                    'profile_type' => get_class($profileModel),
                    'profile_id' => $profileModel->id,
                ]);
            }
        }

        // If user is not associated, deny authorization
        if (!$isAssociated) {
            return false;
        }

        // --- Compare Hash ---
        if ($emailToVerify === null) {
            Log::error("Authorization failed: Could not determine email to verify for " . class_basename($profileModel) . " ID {$profileModel->id}");
             return false; // Should not happen if $isAssociated is true, but safety check
        }

        $routeHash = (string) $this->route('hash');
        if (!hash_equals(sha1($emailToVerify), $routeHash)) {
            Log::error("Email hash mismatch for " . class_basename($profileModel) . " ID {$profileModel->id}. Email: {$emailToVerify}, Route Hash: {$routeHash}");
            return false;
        }

        // --- Authorization Successful ---
        $this->profileModel = $profileModel;
        Log::info("Authorization successful for email verification of " . class_basename($profileModel) . " id: " . $profileModel->id . " by user id: " . $loggedInUser->id );
        return true;
    }

    
    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
                //
            ];
    }

    /**
     * Fulfill the email verification request.
     *
     * @return void
     */
    public function fulfill()
    {
        Log::info('ProfileEmailVerificationRequest::fulfill() called', [
            'profileModel_class' => $this->profileModel ? get_class($this->profileModel) : 'null',
            'profileModel_id' => $this->profileModel?->id,
            'hasVerifiedEmail' => $this->profileModel?->hasVerifiedEmail(),
            'email_verified_at_before' => $this->profileModel?->email_verified_at,
        ]);

        if (!$this->profileModel->hasVerifiedEmail()) {
            $result = $this->profileModel->markEmailAsVerified();

            Log::info('ProfileEmailVerificationRequest::fulfill() markEmailAsVerified result', [
                'result' => $result,
                'email_verified_at_after' => $this->profileModel->fresh()->email_verified_at,
            ]);

            event(new ProfileVerified($this->profileModel));

            Log::info('ProfileEmailVerificationRequest::fulfill() ProfileVerified event dispatched');
        } else {
            Log::info('ProfileEmailVerificationRequest::fulfill() email already verified, skipping');
        }
    }

    /**
     * Configure the validator instance.
     *
     * @param  \Illuminate\Validation\Validator  $validator
     * @return \Illuminate\Validation\Validator
     */
    public function withValidator(Validator $validator)
    {
        return $validator;
    }
}
