<?php

namespace App\Http\Livewire\Traits;

use App\Helpers\ProfileAuthorizationHelper;
use Illuminate\Support\Facades\Log;

/**
 * Requires Admin Authorization Trait
 *
 * Provides reusable admin authorization checks for Livewire components.
 * Prevents IDOR attacks and cross-guard access by validating every sensitive
 * operation, not just the initial component mount.
 *
 * CRITICAL: mount() protection alone is insufficient because Livewire methods
 * can be called directly after the component loads, bypassing mount() checks.
 *
 * Usage:
 * 1. Add trait to component: use RequiresAdminAuthorization;
 * 2. Call at start of sensitive methods: $this->authorizeAdminAccess();
 *
 * Example:
 * public function deletePost($id)
 * {
 *     $this->authorizeAdminAccess(); // CRITICAL: Check on every call
 *
 *     // Safe to proceed with deletion
 *     Post::destroy($id);
 * }
 */
trait RequiresAdminAuthorization
{
    /**
     * Cached authorization result to avoid repeated checks within same request
     *
     * @var bool|null
     */
    private $adminAuthorizationChecked = null;

    /**
     * Authorize admin access for the current operation.
     *
     * This method MUST be called at the start of every sensitive operation
     * (create, update, delete, etc.) to prevent unauthorized access.
     *
     * Validates:
     * - Active profile exists in session
     * - Profile ownership via ProfileAuthorizationHelper (prevents cross-guard attacks)
     * - Admin or central bank (level=0) permissions
     *
     * @param bool $forceRecheck Force a new authorization check even if already checked
     * @return void
     * @throws \Symfony\Component\HttpKernel\Exception\HttpException (403 or 401)
     */
    protected function authorizeAdminAccess(bool $forceRecheck = false): void
    {
        // Use cached result unless force recheck
        if (!$forceRecheck && $this->adminAuthorizationChecked === true) {
            return;
        }

        // Get active profile from session
        $activeProfileType = session('activeProfileType');
        $activeProfileId = session('activeProfileId');

        if (!$activeProfileType || !$activeProfileId) {
            Log::warning('RequiresAdminAuthorization: No active profile in session', [
                'component' => static::class,
                'method' => debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1]['function'] ?? 'unknown',
                'ip_address' => request()->ip(),
            ]);

            abort(403, __('No active profile selected'));
        }

        $profile = $activeProfileType::find($activeProfileId);

        if (!$profile) {
            Log::warning('RequiresAdminAuthorization: Active profile not found', [
                'component' => static::class,
                'active_profile_type' => $activeProfileType,
                'active_profile_id' => $activeProfileId,
                'method' => debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1]['function'] ?? 'unknown',
                'ip_address' => request()->ip(),
            ]);

            abort(403, __('Active profile not found'));
        }

        // Validate profile ownership using ProfileAuthorizationHelper
        // This prevents cross-guard attacks (e.g., web user accessing admin profile)
        ProfileAuthorizationHelper::authorize($profile);

        // Verify admin or central bank permissions
        if ($profile instanceof \App\Models\Admin) {
            // Admin access OK
            $this->adminAuthorizationChecked = true;
            return;
        }

        if ($profile instanceof \App\Models\Bank) {
            // Only central bank (level 0) can access admin functions
            if ($profile->level === 0) {
                $this->adminAuthorizationChecked = true;
                return;
            }

            Log::warning('RequiresAdminAuthorization: Non-central bank attempted admin operation', [
                'component' => static::class,
                'method' => debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1]['function'] ?? 'unknown',
                'bank_id' => $profile->id,
                'bank_level' => $profile->level,
                'ip_address' => request()->ip(),
            ]);

            abort(403, __('Central bank access required for admin operations'));
        }

        // Not admin or central bank
        Log::warning('RequiresAdminAuthorization: Unauthorized profile type attempted admin operation', [
            'component' => static::class,
            'method' => debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1]['function'] ?? 'unknown',
            'profile_type' => get_class($profile),
            'profile_id' => $profile->id,
            'ip_address' => request()->ip(),
        ]);

        abort(403, __('Admin or central bank access required'));
    }

    /**
     * Reset authorization cache.
     *
     * Call this if you need to force a fresh authorization check
     * (e.g., after switching profiles within the same component lifecycle).
     *
     * @return void
     */
    protected function resetAdminAuthorization(): void
    {
        $this->adminAuthorizationChecked = null;
    }

    /**
     * Check if admin access is authorized without throwing an exception.
     *
     * Useful for conditional UI rendering or feature availability checks.
     *
     * @return bool True if authorized, false otherwise
     */
    protected function canPerformAdminActions(): bool
    {
        try {
            $this->authorizeAdminAccess();
            return true;
        } catch (\Throwable $e) {
            return false;
        }
    }
}
