<?php
// =============================================================================
// api/twofa.php — TOTP enrollment + management for the logged-in admin.
//
// Actions:
//   GET  ?action=status                    → { enabled, has_pending_secret }
//   POST { action: 'init' }                → { secret, otpauth_url, issuer, account }
//                                              (stores secret on the row as
//                                              totp_secret but keeps totp_enabled=0)
//   POST { action: 'verify', code: '...' } → { ok: true }  (turns totp_enabled=1)
//   POST { action: 'disable', code: '...' }→ { ok: true }  (clears both fields)
// =============================================================================

require_once __DIR__ . '/_common.php';
require_once __DIR__ . '/../includes/totp.php';

$user = auth_user();
if (!$user) { json_error('unauthorized', 401); }

// 2FA is self-only — viewers can enroll their own TOTP. Skip the global admin
// gate so a viewer can manage their own second factor.
require_csrf_unless_get(true);
list($action, $body) = read_action();

if ($_SERVER['REQUEST_METHOD'] === 'GET' && ($action === '' || $action === 'status')) {
    $row = db_one('SELECT totp_enabled, totp_secret FROM admin_users WHERE id = ?', [(int)$user['id']]);
    json_response([
        'enabled'             => (int)($row['totp_enabled'] ?? 0) === 1,
        'has_pending_secret'  => !empty($row['totp_secret']) && (int)($row['totp_enabled'] ?? 0) === 0,
    ]);
}

if ($action === 'init') {
    // If 2FA is already ENABLED, never let a bare init wipe the existing
    // enrollment — that would let a session-hijacked attacker silently remove
    // 2FA, and a careless user could brick their own authenticator. Require a
    // valid current TOTP code to re-init, same gate as disable.
    $current = db_one('SELECT totp_secret, totp_enabled FROM admin_users WHERE id = ?', [(int)$user['id']]);
    if ((int)($current['totp_enabled'] ?? 0) === 1) {
        $code = isset($body['code']) ? trim((string)$body['code']) : '';
        if ($code === '' || !totp_verify($current['totp_secret'], $code)) {
            json_error('current_code_required', 400);
        }
    }
    $secret = totp_random_secret();
    db_exec('UPDATE admin_users SET totp_secret = ?, totp_enabled = 0 WHERE id = ?',
            [$secret, (int)$user['id']]);

    $cfg = db_one('SELECT display_name FROM config WHERE id = 1');
    $issuer = $cfg['display_name'] ?: 'Master Panel';
    json_response([
        'secret'       => $secret,
        'otpauth_url'  => totp_otpauth_url($secret, $user['username'], $issuer),
        'issuer'       => $issuer,
        'account'      => $user['username'],
    ]);
}

if ($action === 'verify') {
    $code = isset($body['code']) ? trim((string)$body['code']) : '';
    $row = db_one('SELECT totp_secret FROM admin_users WHERE id = ?', [(int)$user['id']]);
    if (empty($row['totp_secret'])) { json_error('no_pending_enrollment', 400); }
    if (!totp_verify($row['totp_secret'], $code)) { json_error('invalid_code', 400); }
    db_exec('UPDATE admin_users SET totp_enabled = 1 WHERE id = ?', [(int)$user['id']]);
    json_response(['ok' => true]);
}

if ($action === 'disable') {
    $code = isset($body['code']) ? trim((string)$body['code']) : '';
    $row = db_one('SELECT totp_secret, totp_enabled FROM admin_users WHERE id = ?', [(int)$user['id']]);
    if ((int)$row['totp_enabled'] !== 1) { json_error('not_enabled', 400); }
    if (!totp_verify($row['totp_secret'], $code)) { json_error('invalid_code', 400); }
    db_exec("UPDATE admin_users SET totp_enabled = 0, totp_secret = '' WHERE id = ?", [(int)$user['id']]);
    json_response(['ok' => true]);
}

json_error('unknown_action', 400);
