<?php

namespace App\Filters;

use App\Models\UserModel;
use App\Services\Auth\JwtService;
use App\Services\Support\TenantContext;
use CodeIgniter\Filters\FilterInterface;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;

/**
 * Runs first in the filter chain for any protected route. Resolves the
 * current user from either the web session or a Bearer JWT (API routes),
 * then populates TenantContext so every downstream Repository/Service can
 * rely on it being set — no controller ever resolves "current agency" itself.
 */
class AuthFilter implements FilterInterface
{
    public function before(RequestInterface $request, $arguments = null)
    {
        $userModel = new UserModel();
        $user = null;

        if ($request->hasHeader('Authorization')) {
            // API request — JWT bearer token
            $header = $request->getHeaderLine('Authorization');
            if (! preg_match('/^Bearer\s+(.+)$/i', $header, $matches)) {
                return $this->unauthorized('Malformed Authorization header.');
            }

            $jwt = new JwtService();
            $payload = $jwt->verifyAccessToken($matches[1]);

            if ($payload === null) {
                return $this->unauthorized('Invalid or expired token.');
            }

            $user = $userModel->findWithRole((int) $payload->sub);
        } else {
            // Web request — session
            $session = session();
            $userId = $session->get('user_id');

            if (! $userId) {
                return redirect()->to('/login')->with('error', 'Please log in to continue.');
            }

            $user = $userModel->findWithRole((int) $userId);
        }

        if ($user === null || $user->status !== 'active') {
            return $this->unauthorized('Account is not active.');
        }

        TenantContext::getInstance()->setUser($user);
    }

    public function after(RequestInterface $request, ResponseInterface $response, $arguments = null)
    {
        // No-op. TenantContext is request-scoped and discarded naturally
        // at end of request (PHP process/worker recycles it per-request
        // under PHP-FPM; explicit reset only needed in long-running
        // workers, handled in queue worker bootstrap instead).
    }

    private function unauthorized(string $message)
    {
        return service('response')
            ->setStatusCode(401)
            ->setJSON(['success' => false, 'data' => null, 'errors' => [['code' => 'UNAUTHENTICATED', 'message' => $message]]]);
    }
}
