<?php

declare(strict_types=1);

namespace App\Middleware;

use App\Core\ErrorHandler;
use App\Core\Logger;
use App\Core\MiddlewareInterface;
use App\Core\Request;
use App\Core\Session;

/**
 * WorkspaceMiddleware — Tenant Boundary Isolation Guard
 *
 * Intercepts Couple and Crew portal requests to enforce database-level
 * workspace isolation. Verifies that the tenant workspace exists, is active,
 * has not been archived/purged, and that the authenticated user belongs to it.
 *
 * Super Admins are permitted to access workspace-specific pages only if operating
 * under a verified and active Support Session context in the database.
 *
 * @package Inveetaire
 * @ref     SPRINT3_PLANNING.md, SPRINT3_EXECUTION_GUIDE.md
 */
class WorkspaceMiddleware implements MiddlewareInterface
{
    /**
     * Handle request validation.
     *
     * @param Request  $request The current HTTP request.
     * @param callable $next    The next middleware or action callback.
     * @return void
     */
    public function handle(Request $request, callable $next): void
    {
        // ── 1. Extract Authenticated Context ──────────────────────────────────
        $userId      = Session::has('auth_user_id') ? (int) Session::get('auth_user_id') : null;
        $role        = Session::has('role_snapshot') ? (string) Session::get('role_snapshot') : null;
        $workspaceId = Session::has('active_workspace_id') ? (int) Session::get('active_workspace_id') : (Session::has('workspace_id') ? (int) Session::get('workspace_id') : null);

        // If AuthMiddleware did not establish session context, deny access.
        if ($userId === null || $role === null) {
            Logger::warning('WorkspaceMiddleware: blocked request due to unauthenticated context', [
                'ip' => $request->getIp()
            ]);
            ErrorHandler::renderForbidden();
            return;
        }

        // ── 2. Super Admin Support Mode Bypass ────────────────────────────────
        if ($role === 'super_admin') {
            if ($workspaceId === null) {
                Logger::warning('WorkspaceMiddleware: Super Admin blocked - missing workspace adoption context', [
                    'admin_user_id' => $userId,
                    'ip'            => $request->getIp()
                ]);
                ErrorHandler::renderForbidden();
                return;
            }

            if (Session::get('super_admin_workspace_mode') !== true) {
                if (!$this->validateSupportSession($userId, $workspaceId)) {
                    Logger::warning('WorkspaceMiddleware: Super Admin blocked - no active support session found', [
                        'admin_user_id'       => $userId,
                        'target_workspace_id' => $workspaceId,
                        'ip'                  => $request->getIp()
                    ]);
                    ErrorHandler::renderForbidden();
                    return;
                }
            }
        } else {
            // ── 3. Couple & Crew Tenant Scoping ───────────────────────────────
            if ($workspaceId === null) {
                Logger::warning('WorkspaceMiddleware: tenant blocked - missing workspace_id in session', [
                    'user_id' => $userId,
                    'role'    => $role,
                    'ip'      => $request->getIp()
                ]);
                ErrorHandler::renderForbidden();
                return;
            }

            // Verify workspace exists, is active, is not archived or purged
            $workspace = $this->getWorkspace($workspaceId);
            if ($workspace === null) {
                Logger::warning('WorkspaceMiddleware: tenant blocked - workspace does not exist', [
                    'workspace_id' => $workspaceId,
                    'user_id'      => $userId,
                    'ip'           => $request->getIp()
                ]);
                ErrorHandler::renderForbidden();
                return;
            }

            $status   = (string) ($workspace['workspace_status'] ?? '');
            $purgedAt = $workspace['purged_at'] ?? null;

            if ($status === 'archived' || $status === 'purged' || $purgedAt !== null) {
                Logger::warning('WorkspaceMiddleware: tenant blocked - workspace archived or purged', [
                    'workspace_id'     => $workspaceId,
                    'workspace_status' => $status,
                    'user_id'          => $userId,
                    'ip'               => $request->getIp()
                ]);
                // Expired/deactivated workspace invalidates active session immediately
                Session::destroy();
                ErrorHandler::renderForbidden();
                return;
            }

            // Verify authenticated user belongs to the workspace and is active
            $user = $this->getUser($userId);
            if ($user === null) {
                Logger::warning('WorkspaceMiddleware: tenant blocked - user record not found', [
                    'user_id' => $userId,
                    'ip'      => $request->getIp()
                ]);
                ErrorHandler::renderForbidden();
                return;
            }

            $userIsActive    = (int) ($user['is_active'] ?? 0);

            if ($userIsActive !== 1) {
                Logger::warning('WorkspaceMiddleware: tenant blocked - inactive user', [
                    'user_id' => $userId,
                    'ip'      => $request->getIp()
                ]);
                ErrorHandler::renderForbidden();
                return;
            }

            if ($role === 'crew') {
                if (!$this->isCrewAssigned($userId, $workspaceId)) {
                    Logger::warning('WorkspaceMiddleware: Crew blocked - not assigned to workspace', [
                        'user_id'             => $userId,
                        'target_workspace_id' => $workspaceId,
                        'ip'                  => $request->getIp()
                    ]);
                    ErrorHandler::renderForbidden();
                    return;
                }
            } else {
                $userWorkspaceId = $user['workspace_id'] !== null ? (int) $user['workspace_id'] : null;
                if ($userWorkspaceId !== $workspaceId) {
                    Logger::warning('WorkspaceMiddleware: Couple blocked - workspace mismatch', [
                        'user_id'             => $userId,
                        'user_workspace_id'   => $userWorkspaceId,
                        'target_workspace_id' => $workspaceId,
                        'ip'                  => $request->getIp()
                    ]);
                    ErrorHandler::renderForbidden();
                    return;
                }
            }
        }

        // ── 4. Proceed ────────────────────────────────────────────────────────
        $next($request);
    }

    /**
     * Validate active support session in database for Super Admin.
     *
     * @param int $adminId
     * @param int $workspaceId
     * @return bool
     */
    private function validateSupportSession(int $adminId, int $workspaceId): bool
    {
        try {
            $db = \App\Core\Database::getConnection();
            $stmt = $db->prepare('
                SELECT id 
                FROM support_sessions 
                WHERE admin_user_id = :admin_id 
                  AND target_workspace_id = :workspace_id 
                  AND is_active = 1 
                  AND closed_at IS NULL 
                LIMIT 1
            ');
            $stmt->execute([
                'admin_id'     => $adminId,
                'workspace_id' => $workspaceId
            ]);
            return $stmt->fetch() !== false;
        } catch (\Throwable $e) {
            Logger::error('WorkspaceMiddleware: support session check database error', [
                'error' => $e->getMessage()
            ]);
            return false;
        }
    }

    /**
     * Retrieve workspace configuration.
     *
     * @param int $workspaceId
     * @return array<string, mixed>|null
     */
    private function getWorkspace(int $workspaceId): ?array
    {
        try {
            $db = \App\Core\Database::getConnection();
            $stmt = $db->prepare('
                SELECT id, workspace_status, purged_at 
                FROM workspaces 
                WHERE id = :workspace_id 
                LIMIT 1
            ');
            $stmt->execute(['workspace_id' => $workspaceId]);
            $res = $stmt->fetch(\PDO::FETCH_ASSOC);
            return $res !== false ? $res : null;
        } catch (\Throwable $e) {
            Logger::error('WorkspaceMiddleware: workspace query database error', [
                'error' => $e->getMessage()
            ]);
            return null;
        }
    }

    /**
     * Retrieve user details.
     *
     * @param int $userId
     * @return array<string, mixed>|null
     */
    private function getUser(int $userId): ?array
    {
        try {
            $db = \App\Core\Database::getConnection();
            $stmt = $db->prepare('
                SELECT id, workspace_id, is_active 
                FROM users 
                WHERE id = :user_id 
                LIMIT 1
            ');
            $stmt->execute(['user_id' => $userId]);
            $res = $stmt->fetch(\PDO::FETCH_ASSOC);
            return $res !== false ? $res : null;
        } catch (\Throwable $e) {
            Logger::error('WorkspaceMiddleware: user query database error', [
                'error' => $e->getMessage()
            ]);
            return null;
        }
    }

    /**
     * Verify if a crew user is assigned to a specific workspace and active.
     */
    private function isCrewAssigned(int $userId, int $workspaceId): bool
    {
        try {
            $db = \App\Core\Database::getConnection();
            $stmt = $db->prepare('
                SELECT id 
                FROM crew_accounts 
                WHERE user_id = :user_id 
                  AND workspace_id = :workspace_id 
                  AND is_active = 1
                LIMIT 1
            ');
            $stmt->execute([
                'user_id'      => $userId,
                'workspace_id' => $workspaceId
            ]);
            return $stmt->fetch() !== false;
        } catch (\Throwable $e) {
            return false;
        }
    }
}
