<?php

use MintyPHP\Http\ApiAuth;
use MintyPHP\Http\ApiBootstrap;
use MintyPHP\Http\ApiResponse;
use MintyPHP\Repository\Auth\ApiTokenRepository;
use MintyPHP\Repository\Tenant\TenantRepository;
use MintyPHP\Service\Auth\AuthServicesFactory;

ApiBootstrap::init();
$apiTokenService = (new AuthServicesFactory())->createApiTokenService();
$apiTokenRepository = new ApiTokenRepository();

$userId = ApiAuth::userId();
if ($userId <= 0) {
    ApiResponse::unauthorized();
}

ApiAuth::requireSelfManageTokens();

$method = strtoupper($_SERVER['REQUEST_METHOD'] ?? 'GET');

if ($method === 'GET') {
    $limit = (int) ($_GET['limit'] ?? 50);
    if ($limit < 1) {
        $limit = 1;
    } elseif ($limit > 100) {
        $limit = 100;
    }

    $scopedTenantId = ApiAuth::scopedTenantId();
    $tokens = $apiTokenRepository->listByUserId($userId, $limit);
    $tenantIds = [];
    foreach ($tokens as $token) {
        $tokenTenantId = isset($token['tenant_id']) ? (int) $token['tenant_id'] : 0;
        if ($tokenTenantId > 0) {
            $tenantIds[] = $tokenTenantId;
        }
    }
    $tenantIds = array_values(array_unique($tenantIds));
    $tenantUuidById = [];
    if ($tenantIds) {
        foreach ((new TenantRepository())->listByIds($tenantIds) as $tenant) {
            $tenantId = (int) ($tenant['id'] ?? 0);
            $tenantUuid = trim((string) ($tenant['uuid'] ?? ''));
            if ($tenantId > 0 && $tenantUuid !== '') {
                $tenantUuidById[$tenantId] = $tenantUuid;
            }
        }
    }

    $rows = [];
    foreach ($tokens as $token) {
        $tokenTenantId = isset($token['tenant_id']) ? (int) $token['tenant_id'] : null;
        if ($tokenTenantId !== null && $tokenTenantId <= 0) {
            $tokenTenantId = null;
        }
        if ($scopedTenantId !== null && $scopedTenantId > 0 && $tokenTenantId !== $scopedTenantId) {
            continue;
        }

        $rows[] = [
            'uuid' => (string) ($token['uuid'] ?? ''),
            'name' => (string) ($token['name'] ?? ''),
            'selector_prefix' => substr((string) ($token['selector'] ?? ''), 0, 8),
            'tenant_uuid' => $tokenTenantId !== null ? ($tenantUuidById[$tokenTenantId] ?? null) : null,
            'last_used_at' => $token['last_used_at'] ?? null,
            'last_ip' => (string) ($token['last_ip'] ?? ''),
            'expires_at' => $token['expires_at'] ?? null,
            'revoked_at' => $token['revoked_at'] ?? null,
            'created' => $token['created'] ?? null,
            'is_current_token' => (int) ($token['id'] ?? 0) === (int) (ApiAuth::tokenId() ?? 0),
        ];
    }

    ApiResponse::success([
        'data' => $rows,
        'limit' => $limit,
    ]);
}

if ($method === 'POST') {
    $input = ApiResponse::readJsonBody();

    $name = trim((string) ($input['name'] ?? ''));
    if ($name === '') {
        ApiResponse::validationError(['name' => [t('Token name is required')]]);
    }
    if (array_key_exists('tenant_id', $input)) {
        ApiResponse::validationError(['tenant_id' => ['use_tenant_uuid']]);
    }

    $tenantId = null;
    $tenantUuid = null;
    $tenantUuidInput = trim((string) ($input['tenant_uuid'] ?? ''));
    if ($tenantUuidInput !== '') {
        $tenant = (new TenantRepository())->findByUuid($tenantUuidInput);
        if (!$tenant) {
            ApiResponse::validationError(['tenant_uuid' => ['invalid_tenant_uuid']]);
        }
        $tenantId = (int) ($tenant['id'] ?? 0);
        if ($tenantId <= 0) {
            ApiResponse::validationError(['tenant_uuid' => ['invalid_tenant_uuid']]);
        }
        $tenantUuid = (string) ($tenant['uuid'] ?? '');
    }

    $scopedTenantId = ApiAuth::scopedTenantId();
    if ($scopedTenantId !== null && $scopedTenantId > 0) {
        $scopedTenant = (new TenantRepository())->find($scopedTenantId);
        $scopedTenantUuid = trim((string) ($scopedTenant['uuid'] ?? ''));
        if ($scopedTenantUuid === '') {
            ApiResponse::forbidden('tenant_scoped_token_forbidden');
        }
        if ($tenantId !== null && $tenantId !== $scopedTenantId) {
            ApiResponse::forbidden('tenant_scoped_token_forbidden');
        }
        $tenantId = $scopedTenantId;
        $tenantUuid = $scopedTenantUuid;
    }

    $expiresAt = null;
    $expiresInput = trim((string) ($input['expires_at'] ?? ''));
    if ($expiresInput !== '') {
        try {
            $expiresDate = new \DateTimeImmutable($expiresInput);
            $expiresDateUtc = $expiresDate->setTimezone(new \DateTimeZone('UTC'));
            $nowUtc = new \DateTimeImmutable('now', new \DateTimeZone('UTC'));
            if ($expiresDateUtc <= $nowUtc) {
                ApiResponse::validationError(['expires_at' => ['must_be_in_future']]);
            }
            $expiresAt = $expiresDateUtc->format('Y-m-d H:i:s');
        } catch (\Exception $e) {
            ApiResponse::validationError(['expires_at' => ['invalid_datetime']]);
        }
    }

    $currentTokenRecord = ApiAuth::tokenRecord();
    $parentExpiresAt = trim((string) ($currentTokenRecord['expires_at'] ?? ''));
    if ($parentExpiresAt !== '') {
        try {
            $parentExpiry = new \DateTimeImmutable($parentExpiresAt, new \DateTimeZone('UTC'));
            $requestedExpiry = $expiresAt !== null
                ? new \DateTimeImmutable($expiresAt, new \DateTimeZone('UTC'))
                : null;
            if ($requestedExpiry === null || $requestedExpiry > $parentExpiry) {
                $expiresAt = $parentExpiresAt;
            }
        } catch (\Exception $e) {
            // Parent token has no parseable expiry — keep requested value.
        }
    }

    $result = $apiTokenService->create($userId, $name, $tenantId, $expiresAt, $userId);
    if (!($result['ok'] ?? false)) {
        $error = (string) ($result['error'] ?? 'create_failed');
        if ($error === 'tenant_not_assigned') {
            ApiResponse::forbidden($error);
        }
        if ($error === 'max_tokens_reached') {
            ApiResponse::error($error, 409);
        }
        ApiResponse::error($error, 422);
    }

    ApiResponse::success([
        'data' => [
            'token_uuid' => (string) ($result['uuid'] ?? ''),
            'token' => (string) ($result['token'] ?? ''),
            'selector_prefix' => substr((string) ($result['selector'] ?? ''), 0, 8),
            'tenant_uuid' => $tenantUuid,
            'expires_at' => $result['expires_at'] ?? null,
        ],
    ], 201);
}

ApiResponse::methodNotAllowed();
