<?php
require_once __DIR__ . '/common.php';

$input = mobile_input();
mobile_boot_tenant($input);
$surveyor = mobile_authorise();

$action = strtolower(trim((string)($input['action'] ?? 'request')));
$surveyorId = (int)($surveyor['id'] ?? 0);
$email = trim((string)($surveyor['email'] ?? ''));

if ($surveyorId <= 0 || $email === '') {
    mobile_json(['ok' => false, 'error' => 'Surveyor email unavailable'], 400);
}

function mobile_passkey_recovery_secret(): string
{
    return hash('sha256', mobile_token_secret() . '|passkey-recovery');
}

function mobile_passkey_recovery_sign(string $payloadEncoded): string
{
    return hash_hmac('sha256', $payloadEncoded, mobile_passkey_recovery_secret());
}

function mobile_passkey_recovery_token(int $surveyorId, string $email, string $code): string
{
    $payload = [
        'type' => 'passkey_recovery',
        'sid' => $surveyorId,
        'email' => $email,
        'code_hash' => hash('sha256', $code),
        'iat' => time(),
        'exp' => time() + (10 * 60),
    ];
    $payloadEncoded = mobile_base64url_encode(json_encode($payload, JSON_UNESCAPED_SLASHES));
    return $payloadEncoded . '.' . mobile_passkey_recovery_sign($payloadEncoded);
}

function mobile_passkey_recovery_validate(string $token, string $code, int $surveyorId, string $email): bool
{
    if ($token === '' || strpos($token, '.') === false || $code === '') {
        return false;
    }
    [$payloadEncoded, $signature] = explode('.', $token, 2);
    if (!hash_equals(mobile_passkey_recovery_sign($payloadEncoded), $signature)) {
        return false;
    }
    $payload = json_decode(mobile_base64url_decode($payloadEncoded), true);
    if (!is_array($payload) || ($payload['type'] ?? '') !== 'passkey_recovery') {
        return false;
    }
    if ((int)($payload['sid'] ?? 0) !== $surveyorId || (string)($payload['email'] ?? '') !== $email) {
        return false;
    }
    if ((int)($payload['exp'] ?? 0) < time()) {
        return false;
    }
    return hash_equals((string)($payload['code_hash'] ?? ''), hash('sha256', $code));
}

if ($action === 'verify') {
    $code = preg_replace('/\D+/', '', (string)($input['code'] ?? ''));
    $recoveryToken = trim((string)($input['recovery_token'] ?? ''));
    if (!mobile_passkey_recovery_validate($recoveryToken, $code, $surveyorId, $email)) {
        mobile_json(['ok' => false, 'error' => 'Invalid or expired recovery code'], 403);
    }
    mobile_json(['ok' => true]);
}

$code = (string)random_int(100000, 999999);
$recoveryToken = mobile_passkey_recovery_token($surveyorId, $email, $code);
$name = trim((string)($surveyor['forename'] ?? '') . ' ' . (string)($surveyor['surname'] ?? ''));
$tenantName = defined('TENANT_URL') ? TENANT_URL : ($GLOBALS['path'] ?? 'EnRep');
$subject = 'EnRep Mobile passkey recovery code';
$body = "Hello" . ($name !== '' ? " $name" : '') . ",\n\n"
    . "Your EnRep Mobile passkey recovery code is: $code\n\n"
    . "This code expires in 10 minutes. If you did not request this code, please ignore this email.\n\n"
    . "Tenant: $tenantName\n";
$headers = [
    'From: EnRep Mobile <no-reply@enrep.uk>',
    'Reply-To: no-reply@enrep.uk',
    'Content-Type: text/plain; charset=UTF-8',
];

if (!mail($email, $subject, $body, implode("\r\n", $headers))) {
    mobile_json(['ok' => false, 'error' => 'Unable to send recovery email'], 500);
}

mobile_json([
    'ok' => true,
    'recovery_token' => $recoveryToken,
    'email_hint' => preg_replace('/(^.).*(@.*$)/', '$1***$2', $email),
    'expires_in' => 10 * 60,
]);
