<?php

declare(strict_types=1);

/**
 * EnRep Tenant 2FA library
 * Expects tenant config.php to have created $con (mysqli) before inclusion.
 * Provides:
 *   - tenant_trust_ok(mysqli $db, int $admin_id): bool
 *   - tenant_2fa_send_code(mysqli $db, int $admin_id, string $email): bool
 *   - tenant_2fa_set_trusted(mysqli $db, int $admin_id): bool
 *
 * Tables required in tenant DB:
 *   admin_trusted_devices(admin_id INT, device_id CHAR(36), device_fingerprint CHAR(64), created_at DATETIME, last_used_at DATETIME)
 *   admin_2fa_codes(admin_id INT, code CHAR(6), expires_at DATETIME, used TINYINT(1), created_at DATETIME)
 */

/* ---------- helpers ---------- */

function _ua_fp(): string
{
    // Relaxed fingerprint to avoid false negatives across networks.
    $ua = $_SERVER['HTTP_USER_AGENT'] ?? '';
    return hash('sha256', $ua);
}

function _code6(): string
{
    return str_pad((string)random_int(0, 999999), 6, '0', STR_PAD_LEFT);
}

function _uuid(): string
{
    $d = random_bytes(16);
    $d[6] = chr((ord($d[6]) & 0x0f) | 0x40);
    $d[8] = chr((ord($d[8]) & 0x3f) | 0x80);
    return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($d), 4));
}

/**
 * Host-only cookie (no domain attribute) so it always sets on the tenant origin.
 * Returns true if PHP accepted the setcookie call.
 */
function _set_trust_cookie(string $deviceId): bool
{
    $key = hash('sha256', 'enrep-tenant-trust-key'); // optionally move to config
    $sig = hash_hmac('sha256', $deviceId, $key);
    $secure = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off');

    return setcookie('enrep_trust', $deviceId . '.' . $sig, [
        'expires'  => time() + 60 * 60 * 24 * 365 * 2, // 2 years
        'path'     => '/',
        // 'domain' => null,  // host-only cookie (omit domain key entirely)
        'secure'   => $secure,
        'httponly' => true,
        'samesite' => 'Lax',
    ]);
}

function _read_trust_cookie(): array
{
    $v = $_COOKIE['enrep_trust'] ?? '';
    if ($v === '' || $v === null) return ['', ''];
    $p = explode('.', $v, 2);
    return [$p[0] ?? '', $p[1] ?? ''];
}

/* ---------- public API ---------- */

function tenant_trust_ok(mysqli $db, int $admin_id): bool
{
    [$deviceId, $sig] = _read_trust_cookie();
    if ($deviceId === '' || $sig === '') return false;

    $key = hash('sha256', 'enrep-tenant-trust-key');
    $calc = hash_hmac('sha256', $deviceId, $key);
    if (!hash_equals($calc, $sig)) return false;

    $fp = _ua_fp();
    $stmt = $db->prepare("SELECT id FROM admin_trusted_devices WHERE admin_id=? AND device_id=? AND device_fingerprint=? LIMIT 1");
    if (!$stmt) {
        // error_log('2FA trust_ok prepare failed: '.$db->errno.' '.$db->error);
        return false;
    }
    $stmt->bind_param('iss', $admin_id, $deviceId, $fp);
    if (!$stmt->execute()) {
        // error_log('2FA trust_ok exec failed: '.$stmt->errno.' '.$stmt->error);
        return false;
    }
    $stmt->store_result();
    return ($stmt->num_rows === 1);
}

function tenant_2fa_send_code(mysqli $db, int $admin_id, string $email): bool
{
    $code = _code6();
    $exp  = (new DateTime('+10 minutes'))->format('Y-m-d H:i:s');

    $stmt = $db->prepare("INSERT INTO admin_2fa_codes (admin_id, code, expires_at) VALUES (?,?,?)");
    if (!$stmt) {
        // error_log('2FA prepare failed: '.$db->errno.' '.$db->error);
        return false;
    }
    if (!$stmt->bind_param('iss', $admin_id, $code, $exp)) {
        // error_log('2FA bind failed: '.$stmt->errno.' '.$stmt->error);
        return false;
    }
    if (!$stmt->execute()) {
        // error_log('2FA exec failed: '.$stmt->errno.' '.$stmt->error);
        return false;
    }

    // send email (replace with your mailer if needed)
    $subject = 'Your EnRep verification code';
    $body    = "Code: {$code}\nExpires in 10 minutes.";
    $from    = "From: no-reply@" . ($_SERVER['HTTP_HOST'] ?? 'enrep.local');

    return mail($email, $subject, $body, $from);
}

function tenant_2fa_set_trusted(mysqli $db, int $admin_id): bool
{
    $deviceId = _uuid();
    $fp = _ua_fp();

    $stmt = $db->prepare("INSERT INTO admin_trusted_devices (admin_id, device_id, device_fingerprint) VALUES (?,?,?)");
    if (!$stmt) {
        // error_log('2FA trust insert prepare failed: '.$db->errno.' '.$db->error);
        return false;
    }
    if (!$stmt->bind_param('iss', $admin_id, $deviceId, $fp)) {
        // error_log('2FA trust insert bind failed: '.$stmt->errno.' '.$stmt->error);
        return false;
    }
    if (!$stmt->execute()) {
        // error_log('2FA trust insert exec failed: '.$stmt->errno.' '.$stmt->error);
        return false;
    }

    return _set_trust_cookie($deviceId);
}