<?php

namespace App\Libraries;

use App\Models\ApiKeyModel;
use CodeIgniter\HTTP\IncomingRequest;

class ApiKeyManager
{
    public const AVAILABLE_SCOPES = [
        'sites:read',
        'sites:write',
        'turbines:read',
        'turbines:write',
        'maintenance:read',
        'maintenance:write',
        'blockchain:read',
        'audit:read',
        'facilities:read',
        'facilities:write',
        'meters:read',
        'meters:write',
        'readings:read',
        'readings:write',
        'certificates:read',
        'certificates:write',
        'verify:read',
    ];

    public const PUBLIC_SCOPES = [
        'sites:read',
        'sites:write',
        'turbines:read',
        'turbines:write',
        'maintenance:read',
        'maintenance:write',
        'blockchain:read',
        'audit:read',
    ];

    public function createKey(
        int $organizationId,
        string $name,
        array $scopes,
        ?int $createdByUserId = null,
        ?string $expiresAt = null
    ): array {
        $token = 'qtm_live_' . strtolower(bin2hex(random_bytes(24)));
        $cleanScopes = $this->normalizeScopes($scopes);
        $model = new ApiKeyModel();

        $id = $model->insert([
            'organization_id' => $organizationId,
            'created_by_user_id' => $createdByUserId,
            'name' => $name,
            'key_prefix' => substr($token, 0, 16),
            'key_hash' => hash('sha256', $token),
            'scopes' => json_encode($cleanScopes, JSON_UNESCAPED_SLASHES),
            'status' => 'active',
            'expires_at' => $expiresAt ?: null,
        ], true);

        return [
            'id' => $id,
            'token' => $token,
        ];
    }

    public function authenticateRequest(IncomingRequest $request): ?array
    {
        $header = trim((string) $request->getHeaderLine('Authorization'));
        if ($header === '' || ! preg_match('/^Bearer\s+(.+)$/i', $header, $matches)) {
            return null;
        }

        $token = trim($matches[1]);
        if ($token === '') {
            return null;
        }

        $model = new ApiKeyModel();
        $apiKey = $model->findActiveByHash(hash('sha256', $token));
        if (! $apiKey) {
            return null;
        }

        $model->update((int) $apiKey['id'], ['last_used_at' => date('Y-m-d H:i:s')]);

        return $apiKey;
    }

    public function allows(array $apiKey, string $scope): bool
    {
        $scopes = $apiKey['scope_list'] ?? [];

        return in_array($scope, $scopes, true) || in_array('*', $scopes, true);
    }

    public function normalizeScopes(array $scopes): array
    {
        $scopes = array_values(array_unique(array_filter($scopes, static fn ($scope) => is_string($scope) && $scope !== '')));

        if ($scopes === [] || in_array('*', $scopes, true)) {
            return ['*'];
        }

        return array_values(array_intersect(self::AVAILABLE_SCOPES, $scopes));
    }
}
