<?php

declare(strict_types=1);

namespace App\Http\Middleware;

use App\Models\ImpersonationToken;
use App\Services\Pd\ImpersonationExpiryService;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Symfony\Component\HttpFoundation\Response;

/**
 * G7-B: на web-запросах с активным impersonation-маркером проверяет 60-мин
 * лимит. Истёк (или токен уже неактивен) → завершает токен, шлёт письмо,
 * разлогинивает, чистит маркер. No-op, если маркера нет.
 *
 * Отправка письма делегирована ImpersonationExpiryService (Service-слой) —
 * middleware не зависит от слоя Mail напрямую (deptrac ruleset).
 */
class ImpersonationContext
{
    public function __construct(private readonly ImpersonationExpiryService $expiry) {}

    public function handle(Request $request, Closure $next): Response
    {
        if (! $request->hasSession() || ! $request->session()->has('impersonation')) {
            return $next($request);
        }

        $marker = $request->session()->get('impersonation');
        $token = ImpersonationToken::on('pgsql_supplier')->find($marker['token_id'] ?? 0);

        if ($token === null || ! $token->isSessionActive()) {
            if ($token !== null) {
                $this->expiry->endSession($token);
            }
            Auth::guard('web')->logout();
            $request->session()->forget('impersonation');
            $request->session()->invalidate();
            $request->session()->regenerateToken();

            // Завершаем текущий запрос немедленно — auth:sanctum уже мог
            // резолвить user'а из сессии, поэтому не передаём $next, а
            // возвращаем 401 явно, чтобы клиент знал о разрыве сессии.
            if ($request->expectsJson()) {
                return response()->json(['message' => 'Сессия impersonation истекла.'], 401);
            }

            return redirect('/login');
        }

        return $next($request);
    }
}
