<?php

use MintyPHP\Http\ApiBootstrap;
use MintyPHP\Http\ApiResponse;
use MintyPHP\Repository\Tenant\TenantRepository;
use MintyPHP\Service\Auth\AuthServicesFactory;
use MintyPHP\Service\Security\SecurityServicesFactory;
use MintyPHP\Service\User\UserServicesFactory;

ApiBootstrap::init();
ApiResponse::requireMethod('POST');

$input = ApiResponse::readJsonBody();

// ---- Login-specific rate limits (stricter than the general API rate limit in ApiBootstrap) ----
$rateLimiter = (new SecurityServicesFactory())->createRateLimiterService();
$ip = $_SERVER['REMOTE_ADDR'] ?? '';

$ipResult = $rateLimiter->isBlocked('api.auth.login.ip', $ip);
if (!($ipResult['allowed'] ?? true)) {
    ApiResponse::tooManyRequests((int) ($ipResult['retry_after'] ?? 60));
}

// ---- Input ----
$email = strtolower(trim((string) ($input['email'] ?? '')));
$password = (string) ($input['password'] ?? '');
$tokenName = trim((string) ($input['token_name'] ?? '')) ?: 'Login';
$tenantUuid = trim((string) ($input['tenant_uuid'] ?? ''));

$validationErrors = [];
if ($email === '') {
    $validationErrors['email'] = ['required'];
}
if ($password === '') {
    $validationErrors['password'] = ['required'];
}
if ($validationErrors) {
    ApiResponse::validationError($validationErrors);
}

// ---- Email+IP rate limit ----
$emailKey = $email . '|' . $ip;
$emailResult = $rateLimiter->isBlocked('api.auth.login.email_ip', $emailKey);
if (!($emailResult['allowed'] ?? true)) {
    ApiResponse::tooManyRequests((int) ($emailResult['retry_after'] ?? 60));
}

// ---- User lookup ----
$userReadRepository = (new UserServicesFactory())->createUserReadRepository();
$user = $userReadRepository->findByEmail($email);
if (!$user) {
    $rateLimiter->registerFailure('api.auth.login.ip',       $ip,       10, 600, 300);
    $rateLimiter->registerFailure('api.auth.login.email_ip', $emailKey,  5, 900, 900);
    ApiResponse::error('invalid_credentials', 401);
}

// ---- Account checks ----
if (!(int) ($user['active'] ?? 0)) {
    $rateLimiter->registerFailure('api.auth.login.ip',       $ip,       10, 600, 300);
    $rateLimiter->registerFailure('api.auth.login.email_ip', $emailKey,  5, 900, 900);
    ApiResponse::error('account_inactive', 401);
}

if (empty($user['email_verified_at'])) {
    $rateLimiter->registerFailure('api.auth.login.ip',       $ip,       10, 600, 300);
    $rateLimiter->registerFailure('api.auth.login.email_ip', $emailKey,  5, 900, 900);
    ApiResponse::error('invalid_credentials', 401);
}

// ---- Password verification ----
if (!password_verify($password, (string) ($user['password'] ?? ''))) {
    $rateLimiter->registerFailure('api.auth.login.ip',       $ip,       10, 600, 300);
    $rateLimiter->registerFailure('api.auth.login.email_ip', $emailKey,  5, 900, 900);
    ApiResponse::error('invalid_credentials', 401);
}

// ---- 2FA stub ----
// When TOTP is implemented, intercept here if totp_secret is non-empty:
// return a short-lived challenge token instead of issuing a full API token.
// Example: ApiResponse::success(['requires_2fa' => true, 'challenge_token' => '...'], 200);
// $totpSecret = trim((string) ($user['totp_secret'] ?? ''));
// if ($totpSecret !== '') { /* TODO: 2FA challenge flow */ }

// ---- Successful login: reset email+IP rate limit ----
$rateLimiter->reset('api.auth.login.email_ip', $emailKey);

// ---- Optional tenant scope ----
$tenantId = null;
if ($tenantUuid !== '') {
    $tenant = (new TenantRepository())->findByUuid($tenantUuid);
    if (!$tenant) {
        ApiResponse::error('invalid_tenant_uuid', 422);
    }
    $tenantId = (int) ($tenant['id'] ?? 0);
    if ($tenantId <= 0) {
        ApiResponse::error('invalid_tenant_uuid', 422);
    }
    $userId = (int) ($user['id'] ?? 0);
    $userTenantIds = (new AuthServicesFactory())->createAuthScopeGateway()->getUserTenantIds($userId);
    if (!in_array($tenantId, $userTenantIds, true)) {
        ApiResponse::error('tenant_not_assigned', 403);
    }
}

// ---- Create token ----
$userId = (int) ($user['id'] ?? 0);
$result = (new AuthServicesFactory())->createApiTokenService()->create(
    $userId,
    $tokenName,
    $tenantId,
    null,    // expiresAt null → uses getApiTokenDefaultTtlDays() from settings
    $userId  // createdBy = self-issued
);

if (!($result['ok'] ?? false)) {
    $error = (string) ($result['error'] ?? 'create_failed');
    if ($error === 'max_tokens_reached') {
        ApiResponse::error($error, 409);
    }
    ApiResponse::error($error, 422);
}

ApiResponse::success([
    'data' => [
        'token'      => (string) ($result['token'] ?? ''),
        'token_uuid' => (string) ($result['uuid'] ?? ''),
        'expires_at' => $result['expires_at'] ?? null,
    ],
], 201);
