<?php

declare(strict_types=1);

namespace App\Services\Auth;

use App\Models\PlatformUser;
use App\Models\ManagedEnvironment;
use App\Services\Intune\AuditLogger;
use Carbon\CarbonImmutable;
use Illuminate\Contracts\Session\Session;

class BreakGlassSession
{
    private const KEY_PREFIX = 'system.break_glass.';

    public function __construct(
        private readonly Session $session,
        private readonly AuditLogger $auditLogger,
    ) {}

    public function isEnabled(): bool
    {
        return (bool) config('tenantpilot.break_glass.enabled', false);
    }

    public function ttlMinutes(): int
    {
        return (int) config('tenantpilot.break_glass.ttl_minutes', 15);
    }

    public function isActive(): bool
    {
        if (! $this->isEnabled()) {
            return false;
        }

        $expiresAt = $this->expiresAt();

        if (! $expiresAt instanceof CarbonImmutable) {
            return false;
        }

        if ($expiresAt->isPast()) {
            $user = auth('platform')->user();

            if ($user instanceof PlatformUser) {
                $this->expire($user);
            } else {
                $this->clear();
            }

            return false;
        }

        return true;
    }

    public function start(PlatformUser $user, string $reason): void
    {
        if (! $this->isEnabled()) {
            return;
        }

        $reason = trim($reason);

        $now = CarbonImmutable::now();
        $expiresAt = $now->addMinutes($this->ttlMinutes());

        $this->session->put(self::KEY_PREFIX.'started_at', $now->toISOString());
        $this->session->put(self::KEY_PREFIX.'expires_at', $expiresAt->toISOString());
        $this->session->put(self::KEY_PREFIX.'reason', $reason);

        $this->audit(
            $user,
            action: 'platform.break_glass.enter',
            status: 'success',
            metadata: [
                'reason' => $reason,
                'started_at' => $now->toISOString(),
                'expires_at' => $expiresAt->toISOString(),
            ],
        );
    }

    public function exit(PlatformUser $user): void
    {
        if (! $this->isEnabled()) {
            return;
        }

        if (! $this->expiresAt() instanceof CarbonImmutable) {
            $this->clear();

            return;
        }

        $metadata = [
            'started_at' => $this->session->get(self::KEY_PREFIX.'started_at'),
            'expires_at' => $this->session->get(self::KEY_PREFIX.'expires_at'),
            'reason' => $this->session->get(self::KEY_PREFIX.'reason'),
        ];

        $this->clear();

        $this->audit(
            $user,
            action: 'platform.break_glass.exit',
            status: 'success',
            metadata: array_filter($metadata, fn ($value): bool => $value !== null),
        );
    }

    public function clear(): void
    {
        $this->session->forget([
            self::KEY_PREFIX.'started_at',
            self::KEY_PREFIX.'expires_at',
            self::KEY_PREFIX.'reason',
        ]);
    }

    public function expiresAt(): ?CarbonImmutable
    {
        $raw = $this->session->get(self::KEY_PREFIX.'expires_at');

        if (! is_string($raw) || $raw === '') {
            return null;
        }

        try {
            return CarbonImmutable::parse($raw);
        } catch (\Throwable) {
            return null;
        }
    }

    private function expire(PlatformUser $user): void
    {
        $metadata = [
            'started_at' => $this->session->get(self::KEY_PREFIX.'started_at'),
            'expires_at' => $this->session->get(self::KEY_PREFIX.'expires_at'),
            'reason' => $this->session->get(self::KEY_PREFIX.'reason'),
        ];

        $this->clear();

        $this->audit(
            $user,
            action: 'platform.break_glass.expired',
            status: 'success',
            metadata: array_filter($metadata, fn ($value): bool => $value !== null),
        );
    }

    private function audit(PlatformUser $user, string $action, string $status, array $metadata): void
    {
        $tenant = ManagedEnvironment::query()->where('slug', 'platform')->first();

        if (! $tenant instanceof ManagedEnvironment) {
            return;
        }

        $this->auditLogger->log(
            $tenant,
            action: $action,
            context: [
                'metadata' => $metadata,
            ],
            actorId: (int) $user->getKey(),
            actorEmail: $user->email,
            actorName: $user->name,
            status: $status,
        );
    }
}
