<?php

declare(strict_types=1);

if (isset($_SERVER['HTTP_X_SSL_CLIENT_VERIFY'])) {
    $_SERVER['SSL_CLIENT_VERIFY']   = $_SERVER['HTTP_X_SSL_CLIENT_VERIFY'];
    $_SERVER['SSL_CLIENT_S_DN']     = $_SERVER['HTTP_X_SSL_CLIENT_S_DN'] ?? '';
    $_SERVER['SSL_CLIENT_I_DN']     = $_SERVER['HTTP_X_SSL_CLIENT_I_DN'] ?? '';
    $_SERVER['SSL_CLIENT_M_SERIAL'] = $_SERVER['HTTP_X_SSL_CLIENT_M_SERIAL'] ?? '';
    $_SERVER['SSL_CLIENT_V_END']    = $_SERVER['HTTP_X_SSL_CLIENT_V_END'] ?? '';

    $certPem = $_SERVER['HTTP_X_SSL_CLIENT_CERT'] ?? '';
    if (!empty($certPem)) {
        $_SERVER['SSL_CLIENT_CERT'] = str_replace([' ', "\t"], ["\n", ''], $certPem);
        if (!str_contains($_SERVER['SSL_CLIENT_CERT'], '-----BEGIN')) {
            $_SERVER['SSL_CLIENT_CERT'] = "-----BEGIN CERTIFICATE-----\n"
                . chunk_split(preg_replace('/\s+/', '', $_SERVER['SSL_CLIENT_CERT']), 64, "\n")
                . "-----END CERTIFICATE-----";
        }
    }
}

require_once dirname(__DIR__, 2) . '/src/bootstrap.php';

use MaHerMoSSO\Auth\SmartCardAuth;
use MaHerMoSSO\Auth\CertificateAuth;
use MaHerMoSSO\Auth\PasswordAuth;
use MaHerMoSSO\Auth\TOTPAuth;
use MaHerMoSSO\Database\Database;
use MaHerMoSSO\Security\CSRF;
use MaHerMoSSO\Security\InputValidator;
use MaHerMoSSO\Security\RateLimiter;
use MaHerMoSSO\Security\SecurityHeaders;
use MaHerMoSSO\Session\SessionManager;
use MaHerMoSSO\SSO\SSOProtocol;

SecurityHeaders::noCacheHeaders();

$clientId = $_GET['client_id'] ?? '';
$redirectUri = $_GET['redirect_uri'] ?? '';
$responseType = $_GET['response_type'] ?? '';
$scope = $_GET['scope'] ?? 'openid profile email';
$state = $_GET['state'] ?? '';

$isSSOFlow = !empty($clientId);
$applicationInfo = null;

if ($isSSOFlow) {
    $validation = SSOProtocol::validateAuthorizeRequest([
        'client_id' => $clientId,
        'redirect_uri' => $redirectUri,
        'response_type' => $responseType,
        'scope' => $scope,
        'state' => $state,
    ]);

    if ($validation['valid']) {
        $applicationInfo = $validation['application'];
        $redirectUri = $validation['redirect_uri'];
    } else {
        $isSSOFlow = false;
    }
}

$result = SmartCardAuth::authenticate();
$ip = SessionManager::getClientIP();
$ua = $_SERVER['HTTP_USER_AGENT'] ?? '';

if ($result['success']) {
    $user = $result['user'];
    $authMethod = 'smartcard';
    $certSerial = $result['cert_info']['serial'] ?? null;

    $session = SessionManager::createSession($user, $authMethod, $ip, $ua);
    SessionManager::setSecureCookie('mhsso_token', $session['access_token'], time() + SESSION_LIFETIME);
    SessionManager::setSecureCookie('mhsso_refresh', $session['refresh_token'], time() + REFRESH_TOKEN_LIFETIME);

    try { SessionManager::logLogin($user['id'], $user['username'], $applicationInfo['id'] ?? null, $applicationInfo['name'] ?? null, $authMethod, $ip, $ua, 'success'); }
    catch (\Throwable $e) { error_log('smartcard log error: ' . $e->getMessage()); }

    if ($isSSOFlow && $applicationInfo && $redirectUri) {
        $code = SSOProtocol::createAuthorizationCode(
            $user['id'], $applicationInfo['id'], $redirectUri, $scope, $state, $authMethod, $certSerial
        );
        header('Location: ' . SSOProtocol::buildRedirectUrl($redirectUri, $code, $state));
        exit;
    }

    header('Location: ' . SSO_BASE_URL . '/profile.php');
    exit;
}

$error = $result['error'];
$certInfo = $result['cert_info'] ?? [];
$certType = $certInfo['cert_type'] ?? null;
$linkError = '';

// -----------------------------------------------------------------------------
// Flujo de vinculación de SmartCard con MFA obligatorio si la cuenta lo tiene.
// (Ver comentario extenso en /cert-auth/login.php para el porqué.)
// -----------------------------------------------------------------------------
$linkStep      = 'password';
$linkTotpState = null;
$LINK_TOTP_TTL = 300;

if (!empty($_GET['restart'])) {
    unset($_SESSION['smartcard_link_pending']);
}

if ($error === 'cert_not_linked' && $certType !== null) {
    $stashed = $_SESSION['smartcard_link_pending'] ?? null;
    if (is_array($stashed)
        && ($stashed['expires_at'] ?? 0) > time()
        && ($stashed['thumbprint'] ?? '') === ($certInfo['thumbprint'] ?? '')
        && ($stashed['cert_type'] ?? '') === $certType
    ) {
        $linkTotpState = $stashed;
        $linkStep      = 'totp';
    } else {
        unset($_SESSION['smartcard_link_pending']);
    }
}

$finalizeSmartcardLink = static function (array $linkUser, string $usedAuthMethod)
    use ($certType, $certInfo, $ip, $ua, $isSSOFlow, $applicationInfo, $redirectUri,
         $scope, $state): void {

    $session = SessionManager::createSession($linkUser, 'smartcard', $ip, $ua);
    SessionManager::setSecureCookie('mhsso_token', $session['access_token'], time() + SESSION_LIFETIME);
    SessionManager::setSecureCookie('mhsso_refresh', $session['refresh_token'], time() + REFRESH_TOKEN_LIFETIME);

    try {
        SessionManager::logLogin(
            $linkUser['id'],
            $linkUser['username'],
            $applicationInfo['id'] ?? null,
            $applicationInfo['name'] ?? null,
            $usedAuthMethod,
            $ip,
            $ua,
            'success'
        );
    } catch (\Throwable $e) {
        error_log('smartcard-link log error: ' . $e->getMessage());
    }

    if ($isSSOFlow && $applicationInfo && $redirectUri) {
        $code = SSOProtocol::createAuthorizationCode(
            $linkUser['id'],
            $applicationInfo['id'],
            $redirectUri,
            $scope,
            $state,
            'smartcard',
            $certInfo['serial'] ?? null
        );
        header('Location: ' . SSOProtocol::buildRedirectUrl($redirectUri, $code, $state));
        exit;
    }
    header('Location: ' . SSO_BASE_URL . '/profile.php');
    exit;
};

if ($error === 'cert_not_linked' && $certType !== null && $_SERVER['REQUEST_METHOD'] === 'POST') {
    $csrfTokenPosted = (string) ($_POST['csrf_token'] ?? '');
    $action          = (string) ($_POST['action'] ?? 'smartcard_link_password');

    if (!CSRF::validate($csrfTokenPosted)) {
        $linkError = 'Token de seguridad inválido.';
    } elseif ($action === 'smartcard_link_totp' && $linkTotpState !== null) {
        $totpCode = trim((string) ($_POST['totp_code'] ?? ''));

        if (!RateLimiter::check($ip, 'smartcard_link_totp')) {
            $linkError = 'Demasiados intentos. Espere antes de intentar de nuevo.';
        } elseif ($totpCode === '') {
            $linkError = 'Introduzca el código TOTP.';
        } else {
            $db = Database::getInstance();
            $stmt = $db->prepare('SELECT * FROM sso_users WHERE id = :id LIMIT 1');
            $stmt->execute(['id' => $linkTotpState['user_id']]);
            $linkUser = $stmt->fetch(PDO::FETCH_ASSOC);

            $totpOk    = false;
            $isRecovery = false;

            if (!$linkUser || empty($linkUser['totp_secret'])) {
                $linkError = 'Configuración TOTP no encontrada para el usuario.';
                unset($_SESSION['smartcard_link_pending']);
            } else {
                if (InputValidator::validateTOTPCode($totpCode)) {
                    try {
                        $totpOk = TOTPAuth::verifyCode($linkUser['totp_secret'], $totpCode);
                    } catch (\Throwable $e) {
                        error_log('smartcard-link TOTP verify error: ' . $e->getMessage());
                    }
                }
                if (!$totpOk) {
                    try {
                        $totpOk     = TOTPAuth::verifyRecoveryCode((string) $linkUser['id'], $totpCode);
                        $isRecovery = $totpOk;
                    } catch (\Throwable $e) {
                        error_log('smartcard-link recovery verify error: ' . $e->getMessage());
                    }
                }
                if (!$totpOk) {
                    RateLimiter::hit($ip, 'smartcard_link_totp');
                    $linkError = 'Código TOTP incorrecto. También puede usar un código de recuperación.';
                }
            }

            if ($totpOk && $linkUser) {
                unset($_SESSION['smartcard_link_pending']);
                $linkOk = CertificateAuth::linkSmartCardToUser(
                    $linkUser['id'],
                    $certInfo['serial'] ?? '',
                    $certInfo['thumbprint'] ?? '',
                    CertificateAuth::certTypeLabel($certType)
                );

                if ($linkOk) {
                    $finalizeSmartcardLink(
                        $linkUser,
                        $isRecovery ? 'smartcard_totp_recovery' : 'smartcard_totp'
                    );
                }
                $linkError = 'No se pudo vincular la SmartCard.';
            }
        }
    } else {
        $username = trim($_POST['username'] ?? '');
        $password = (string) ($_POST['password'] ?? '');

        if ($username === '' || $password === '') {
            $linkError = 'Introduzca usuario y contraseña.';
        } elseif (!RateLimiter::check($ip, 'smartcard_link_password')) {
            $linkError = 'Demasiados intentos. Espere antes de intentar de nuevo.';
        } else {
            $authResult = PasswordAuth::authenticate($username, $password);
            if (empty($authResult['success'])) {
                RateLimiter::hit($ip, 'smartcard_link_password');
                $linkError = 'Credenciales incorrectas.';
            } else {
                $linkUser = $authResult['user'];

                if (!empty($authResult['totp_required'])) {
                    $linkTotpState = [
                        'user_id'    => $linkUser['id'],
                        'username'   => $linkUser['username'] ?? null,
                        'cert_type'  => $certType,
                        'thumbprint' => $certInfo['thumbprint'] ?? '',
                        'created_at' => time(),
                        'expires_at' => time() + $LINK_TOTP_TTL,
                    ];
                    $_SESSION['smartcard_link_pending'] = $linkTotpState;
                    $linkStep = 'totp';
                } else {
                    $linkOk = CertificateAuth::linkSmartCardToUser(
                        $linkUser['id'],
                        $certInfo['serial'] ?? '',
                        $certInfo['thumbprint'] ?? '',
                        CertificateAuth::certTypeLabel($certType)
                    );

                    if ($linkOk) {
                        $finalizeSmartcardLink($linkUser, 'smartcard');
                    }
                    $linkError = 'No se pudo vincular la SmartCard.';
                }
            }
        }
    }
}

if ($error !== 'cert_not_linked') {
    SessionManager::logLogin(null, null, $applicationInfo['id'] ?? null, $applicationInfo['name'] ?? null, 'smartcard', $ip, $ua, 'failed', $error);
}

$ssoLoginQuery = $isSSOFlow ? ['client_id' => $clientId, 'redirect_uri' => $redirectUri, 'response_type' => $responseType, 'scope' => $scope, 'state' => $state] : [];
$ssoLoginUrl = SSO_BASE_URL . '/login.php' . ($isSSOFlow ? '?' . http_build_query($ssoLoginQuery) : '');
$csrfToken = CSRF::getToken();
$pageTitle = $error === 'cert_not_linked' ? 'Asociar SmartCard' : 'Error de SmartCard';

include dirname(__DIR__, 2) . '/templates/partials/header.php';
?>

<style nonce="<?= htmlspecialchars($nonce, ENT_QUOTES) ?>">
    .cert-link-title { margin-bottom: 12px; font-size: 1.1rem; }
    .cert-link-lead { font-size: 0.875rem; color: var(--color-text-secondary); margin-bottom: 16px; }
    .cert-link-info { margin-bottom: 16px; }
    .cert-link-info-title { font-size: 0.875rem; margin-bottom: 8px; }
    .cert-link-info-row { font-size: 0.8125rem; margin: 2px 0; }
    .cert-link-user-hint { font-size: 0.875rem; color: var(--color-text-secondary); margin-bottom: 12px; }
    .cert-link-back { margin-top: 16px; text-align: center; }
    .cert-link-restart-form { margin-top: 8px; }
</style>

<div class="login-page">
    <div class="login-container">
        <div class="login-brand">
            <h1>MaHerMo SSO</h1>
            <p>Autenticación con SmartCard</p>
        </div>
        <div class="login-card">

<?php if ($error === 'cert_not_linked' && $certType !== null): ?>
            <h2 class="cert-link-title">Asociar SmartCard <?= htmlspecialchars(CertificateAuth::certTypeLabel($certType)) ?></h2>
            <p class="cert-link-lead">
                <?php if ($linkStep === 'totp'): ?>
                    La cuenta indicada tiene activada la verificación en dos pasos. Introduzca el código de su
                    autenticador (o un código de recuperación) para completar la asociación de la SmartCard.
                <?php else: ?>
                    Esta SmartCard no está vinculada a ninguna cuenta. Introduzca sus credenciales para asociarla.
                <?php endif; ?>
            </p>

            <?php if ($linkError): ?>
                <div class="alert alert-error"><?= htmlspecialchars($linkError) ?></div>
            <?php endif; ?>

            <div class="cert-info-box cert-link-info">
                <h3 class="cert-link-info-title">SmartCard detectada</h3>
                <p class="cert-link-info-row"><strong>Tipo:</strong> <?= htmlspecialchars(CertificateAuth::certTypeLabel($certType)) ?></p>
                <?php if (!empty($certInfo['cn'])): ?>
                    <p class="cert-link-info-row"><strong>Nombre:</strong> <?= htmlspecialchars($certInfo['cn']) ?></p>
                <?php endif; ?>
                <?php if (!empty($certInfo['email'])): ?>
                    <p class="cert-link-info-row"><strong>Correo:</strong> <?= htmlspecialchars($certInfo['email']) ?></p>
                <?php endif; ?>
                <?php if (!empty($certInfo['issuer'])): ?>
                    <p class="cert-link-info-row"><strong>Emisor:</strong> <?= htmlspecialchars($certInfo['issuer']) ?></p>
                <?php endif; ?>
            </div>

            <?php if ($linkStep === 'totp'): ?>
                <?php $linkedUsername = $linkTotpState['username'] ?? ''; ?>
                <?php if ($linkedUsername !== ''): ?>
                    <p class="cert-link-user-hint">Verificando 2FA para <strong><?= htmlspecialchars($linkedUsername) ?></strong>.</p>
                <?php endif; ?>
                <form method="POST" action="<?= htmlspecialchars($_SERVER['REQUEST_URI']) ?>">
                    <input type="hidden" name="csrf_token" value="<?= htmlspecialchars($csrfToken) ?>">
                    <input type="hidden" name="action" value="smartcard_link_totp">
                    <div class="form-group">
                        <label for="sc-link-totp-code">Código TOTP o de recuperación</label>
                        <input
                            type="text"
                            id="sc-link-totp-code"
                            name="totp_code"
                            class="form-input"
                            inputmode="numeric"
                            autocomplete="one-time-code"
                            required
                            autofocus
                            maxlength="30"
                        >
                    </div>
                    <button type="submit" class="btn btn-primary btn-block">Verificar y asociar</button>
                </form>
                <form method="GET" action="/cert-auth/smartcard.php" class="cert-link-restart-form">
                    <?php foreach ($ssoLoginQuery as $k => $v): ?>
                        <input type="hidden" name="<?= htmlspecialchars((string) $k) ?>" value="<?= htmlspecialchars((string) $v) ?>">
                    <?php endforeach; ?>
                    <input type="hidden" name="restart" value="1">
                    <button type="submit" class="btn btn-outline btn-block">Cambiar de cuenta</button>
                </form>
            <?php else: ?>
                <form method="POST" action="<?= htmlspecialchars($_SERVER['REQUEST_URI']) ?>">
                    <input type="hidden" name="csrf_token" value="<?= htmlspecialchars($csrfToken) ?>">
                    <input type="hidden" name="action" value="smartcard_link_password">
                    <div class="form-group">
                        <label for="sc-link-username">Usuario o correo electrónico</label>
                        <input type="text" id="sc-link-username" name="username" class="form-input" required autofocus
                               value="<?= htmlspecialchars($_POST['username'] ?? '') ?>">
                    </div>
                    <div class="form-group">
                        <label for="sc-link-password">Contraseña</label>
                        <input type="password" id="sc-link-password" name="password" class="form-input" required>
                    </div>
                    <button type="submit" class="btn btn-primary btn-block">Asociar SmartCard e iniciar sesión</button>
                </form>
            <?php endif; ?>

            <div class="cert-link-back">
                <a href="<?= htmlspecialchars($ssoLoginUrl) ?>" class="btn btn-outline btn-block">Volver al inicio de sesión</a>
            </div>

<?php else: ?>
            <div class="alert alert-error"><?= htmlspecialchars($error) ?></div>

            <div class="cert-info-box">
                <h3>Requisitos para SmartCard</h3>
                <p>Asegúrese de que:</p>
                <ul class="cert-info-list">
                    <li>La SmartCard está insertada en el lector</li>
                    <li>El lector está conectado y tiene los drivers instalados</li>
                    <li>El certificado de la tarjeta es del DNI electrónico o de Omnipresence TrustCA</li>
                    <li>Su cuenta está vinculada a esta tarjeta</li>
                </ul>
            </div>

            <?php if (!empty($certInfo)): ?>
                <div class="cert-info-box">
                    <h3>Información del certificado</h3>
                    <?php if (!empty($certInfo['cn'])): ?>
                        <p><strong>Nombre:</strong> <?= htmlspecialchars($certInfo['cn']) ?></p>
                    <?php endif; ?>
                    <?php if (!empty($certInfo['issuer'])): ?>
                        <p><strong>Emisor:</strong> <?= htmlspecialchars($certInfo['issuer']) ?></p>
                    <?php endif; ?>
                </div>
            <?php endif; ?>

            <a href="<?= htmlspecialchars($ssoLoginUrl) ?>" class="btn btn-secondary btn-block">Volver al inicio de sesión</a>
<?php endif; ?>

        </div>
    </div>
</div>

<?php include dirname(__DIR__, 2) . '/templates/partials/footer.php'; ?>
