<?php
// two_factor.php — Two-Factor Authentication settings.
// POST is processed before any HTML output (PRG redirects).
session_start();
include_once("config/db.php");
$uid = (int)($_SESSION['user_id'] ?? 0);

/* ---------- column detection (schema_customer_settings.sql) ---------- */
$has_2fa = false; $has_totp = false;
$twofa_on = false; $codes = []; $totp_secret = null; $totp_on = false;
if ($uid && ($c = $conn->prepare("SELECT twofa_enabled, backup_codes FROM users WHERE id=?"))) {
    $has_2fa = true;
    $c->bind_param("i", $uid); $c->execute();
    $row = $c->get_result()->fetch_assoc() ?: [];
    $twofa_on = (bool)($row['twofa_enabled'] ?? 0);
    $codes    = $row['backup_codes'] ? (json_decode($row['backup_codes'], true) ?: []) : [];
}
if ($uid && ($c2 = $conn->prepare("SELECT totp_secret, totp_enabled FROM users WHERE id=?"))) {
    $has_totp = true;
    $c2->bind_param("i", $uid); $c2->execute();
    $r2 = $c2->get_result()->fetch_assoc() ?: [];
    $totp_secret = $r2['totp_secret'] ?? null;
    $totp_on     = (bool)($r2['totp_enabled'] ?? 0);
}

/* ---------- helpers ---------- */
function gen_backup_codes(int $n = 8): array {
    $out = [];
    for ($i = 0; $i < $n; $i++) $out[] = strtoupper(bin2hex(random_bytes(2))) . '-' . strtoupper(bin2hex(random_bytes(2)));
    return $out;
}
function gen_totp_secret(int $len = 16): string {
    $alpha = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'; $s = '';
    for ($i = 0; $i < $len; $i++) $s .= $alpha[random_int(0, 31)];
    return $s;
}
function base32_decode(string $b32): string {
    $map = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'; $b32 = strtoupper($b32); $bits = ''; $out = '';
    for ($i = 0; $i < strlen($b32); $i++) { $v = strpos($map, $b32[$i]); if ($v === false) continue; $bits .= str_pad(decbin($v), 5, '0', STR_PAD_LEFT); }
    for ($i = 0; $i + 8 <= strlen($bits); $i += 8) $out .= chr(bindec(substr($bits, $i, 8)));
    return $out;
}
function hotp(string $secret, int $counter): int {
    $key = base32_decode($secret);
    $bin = pack('N*', 0) . pack('N*', $counter);
    $h = hash_hmac('sha1', $bin, $key, true);
    $o = ord($h[19]) & 0xf;
    $code = ((ord($h[$o]) & 0x7f) << 24) | ((ord($h[$o + 1]) & 0xff) << 16) | ((ord($h[$o + 2]) & 0xff) << 8) | (ord($h[$o + 3]) & 0xff);
    return $code % 1000000;
}
function totp_verify(string $secret, string $code): bool {
    $code = preg_replace('/\D/', '', $code);
    if (strlen($code) !== 6) return false;
    $t = (int)floor(time() / 30);
    for ($w = -1; $w <= 1; $w++) if (str_pad((string)hotp($secret, $t + $w), 6, '0', STR_PAD_LEFT) === $code) return true;
    return false;
}

$flash_codes = $_SESSION['twofa_new_codes'] ?? null;  unset($_SESSION['twofa_new_codes']);
$totp_error  = $_SESSION['totp_error'] ?? '';          unset($_SESSION['totp_error']);

/* ---------- POST actions ---------- */
if ($uid && $_SERVER['REQUEST_METHOD'] === 'POST') {
    $action = $_POST['action'] ?? '';

    if ($has_2fa && $action === 'toggle') {
        $new = $twofa_on ? 0 : 1;
        if ($new && empty($codes)) {
            $plain = gen_backup_codes();
            $json = json_encode(array_map(fn($x) => password_hash($x, PASSWORD_DEFAULT), $plain));
            $u = $conn->prepare("UPDATE users SET twofa_enabled=?, backup_codes=? WHERE id=?");
            $u->bind_param("isi", $new, $json, $uid); $u->execute();
            $_SESSION['twofa_new_codes'] = $plain;
        } else {
            $u = $conn->prepare("UPDATE users SET twofa_enabled=? WHERE id=?");
            $u->bind_param("ii", $new, $uid); $u->execute();
        }
        header("Location: two_factor.php"); exit;
    }

    if ($has_2fa && $action === 'regen') {
        $plain = gen_backup_codes();
        $json = json_encode(array_map(fn($x) => password_hash($x, PASSWORD_DEFAULT), $plain));
        $u = $conn->prepare("UPDATE users SET backup_codes=? WHERE id=?");
        $u->bind_param("si", $json, $uid); $u->execute();
        $_SESSION['twofa_new_codes'] = $plain;
        header("Location: two_factor.php"); exit;
    }

    if ($has_totp && $action === 'totp_init') {
        $_SESSION['totp_pending'] = gen_totp_secret();
        header("Location: two_factor.php#auth"); exit;
    }
    if ($has_totp && $action === 'totp_cancel') {
        unset($_SESSION['totp_pending']);
        header("Location: two_factor.php"); exit;
    }
    if ($has_totp && $action === 'totp_verify') {
        $pending = $_SESSION['totp_pending'] ?? '';
        $code = $_POST['code'] ?? '';
        if ($pending && totp_verify($pending, $code)) {
            $on = 1;
            $u = $conn->prepare("UPDATE users SET totp_secret=?, totp_enabled=1 WHERE id=?");
            $u->bind_param("si", $pending, $uid); $u->execute();
            unset($_SESSION['totp_pending']);
            header("Location: two_factor.php"); exit;
        }
        $_SESSION['totp_error'] = 'That code didn\'t match. Make sure your device clock is correct and try again.';
        header("Location: two_factor.php#auth"); exit;
    }
    if ($has_totp && $action === 'totp_disable') {
        $u = $conn->prepare("UPDATE users SET totp_secret=NULL, totp_enabled=0 WHERE id=?");
        $u->bind_param("i", $uid); $u->execute();
        unset($_SESSION['totp_pending']);
        header("Location: two_factor.php"); exit;
    }
}

$page_title = 'Security & Privacy';
$active_nav = 'profile';
include("includes/header.php");

$masked_email = $__email;
if (strpos($__email, '@') !== false) {
    [$local, $domain] = explode('@', $__email, 2);
    $masked_email = substr($local, 0, 2) . str_repeat('•', max(2, strlen($local) - 2)) . '@' . $domain;
}
$codes_remaining = count($codes);
$pending = $_SESSION['totp_pending'] ?? '';
$otpauth = $pending ? 'otpauth://totp/' . rawurlencode('Dabil:' . $__email) . '?secret=' . $pending . '&issuer=Dabil&digits=6&period=30' : '';
?>

<style>
.app-topbar { display: none; }
.main-content { padding-top: calc(env(safe-area-inset-top) + 6px); }
.tf-wrap { max-width: 600px; margin: 0 auto; }

.sub-topbar { display: flex; align-items: center; justify-content: space-between; padding: 4px 2px 14px; }
.sub-topbar-left { display: flex; align-items: center; gap: 12px; min-width: 0; }
.sub-topbar .sub-back { width: 36px; height: 36px; border-radius: 50%; display: flex; align-items: center; justify-content: center; color: var(--primary); background: var(--primary-bg); flex-shrink: 0; }
.sub-topbar .sub-title { font-size: 1.1rem; font-weight: 800; letter-spacing: -.02em; color: var(--text); }
.sub-topbar .icon-btn { color: var(--primary); }

.tf-hero { text-align: center; margin-bottom: 22px; }
.tf-hero-icon { width: 64px; height: 64px; border-radius: 18px; background: #fff; box-shadow: 0 6px 20px rgba(15,23,42,.08); display: flex; align-items: center; justify-content: center; margin: 6px auto 12px; color: var(--primary); }
.tf-hero h1 { font-size: 1.2rem; font-weight: 800; letter-spacing: -.02em; margin-bottom: 4px; }
.tf-hero p { font-size: .84rem; color: var(--text-muted); line-height: 1.5; max-width: 320px; margin: 0 auto; }

.tf-card { background: #fff; border-radius: 16px; box-shadow: 0 4px 18px rgba(15,23,42,.06); border: 1px solid var(--border); padding: 16px; margin-bottom: 16px; }
.tf-card-row { display: flex; align-items: center; gap: 14px; }
.tf-ic { width: 40px; height: 40px; border-radius: 11px; background: var(--primary-bg); color: var(--primary); display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
.tf-ic.muted { background: var(--bg); color: var(--text-muted); }
.tf-ic.green { background: var(--success-bg); color: var(--success); }
.tf-meta { flex: 1; min-width: 0; }
.tf-title { font-weight: 700; font-size: .92rem; margin-bottom: 2px; }
.tf-sub { font-size: .78rem; color: var(--text-muted); word-break: break-word; }
.tf-hint { font-size: .78rem; color: var(--text-muted); line-height: 1.5; margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--border); }
.tf-hint.info { background: var(--primary-bg); color: var(--primary); border: none; border-radius: 10px; padding: 10px 12px; display: flex; gap: 8px; align-items: flex-start; margin-top: 12px; }
.tf-hint.info svg { flex-shrink: 0; margin-top: 1px; }

.toggle-switch { position: relative; display: inline-block; width: 50px; height: 28px; flex-shrink: 0; }
.toggle-switch input { opacity: 0; width: 0; height: 0; }
.toggle-slider { position: absolute; cursor: pointer; inset: 0; background: var(--border-dark); border-radius: 30px; transition: .2s; }
.toggle-slider:before { content: ''; position: absolute; width: 22px; height: 22px; left: 3px; bottom: 3px; background: #fff; border-radius: 50%; transition: .2s; box-shadow: 0 1px 3px rgba(0,0,0,.2); }
.toggle-switch input:checked + .toggle-slider { background: var(--primary); }
.toggle-switch input:checked + .toggle-slider:before { transform: translateX(22px); }

.tf-pill { font-size: .72rem; font-weight: 800; padding: 4px 10px; border-radius: 20px; background: var(--bg); color: var(--text-muted); flex-shrink: 0; }
.tf-pill.on { background: var(--success-bg); color: var(--success); }
.tf-btn { border: none; background: var(--primary); color: #fff; font-family: var(--font); font-weight: 700; font-size: .82rem; padding: 10px 18px; border-radius: 10px; cursor: pointer; flex-shrink: 0; }
.tf-btn.ghost { background: var(--primary-bg); color: var(--primary); }
.tf-btn.danger { background: var(--error-bg); color: var(--error); }

/* TOTP setup panel */
.tf-setup { margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--border); }
.tf-setup ol { margin: 0 0 12px; padding-left: 18px; }
.tf-setup li { font-size: .82rem; color: var(--text-muted); line-height: 1.5; margin-bottom: 4px; }
.tf-qr { width: 168px; height: 168px; margin: 6px auto 12px; padding: 10px; background: #fff; border: 1px solid var(--border); border-radius: 12px; display: flex; align-items: center; justify-content: center; }
.tf-key { text-align: center; font-size: .78rem; color: var(--text-muted); margin-bottom: 14px; }
.tf-key code { font-family: ui-monospace, Menlo, monospace; font-weight: 700; letter-spacing: 1px; color: var(--text); background: var(--bg); padding: 6px 10px; border-radius: 8px; display: inline-block; margin-top: 4px; }
.tf-code-input { width: 100%; height: 52px; border: 1.5px solid var(--border); border-radius: 12px; text-align: center; font-size: 1.3rem; font-weight: 800; letter-spacing: 6px; font-family: var(--font); color: var(--text); outline: none; margin-bottom: 12px; }
.tf-code-input:focus { border-color: var(--primary); box-shadow: 0 0 0 3px rgba(34,90,227,.1); }
.tf-setup-actions { display: flex; gap: 10px; }
.tf-setup-actions button { flex: 1; height: 48px; border-radius: 12px; font-weight: 700; font-size: .9rem; font-family: var(--font); cursor: pointer; border: none; }
.tf-verify { background: var(--primary); color: #fff; }
.tf-cancel { background: var(--bg); color: var(--text); border: 1.5px solid var(--border) !important; }

.tf-codes { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-top: 14px; }
.tf-codes code { font-family: ui-monospace, Menlo, monospace; background: var(--bg); border: 1px dashed var(--border-dark); border-radius: 8px; padding: 10px; text-align: center; font-size: .9rem; font-weight: 700; letter-spacing: .5px; }
.tf-codes-actions { display: flex; gap: 10px; margin-top: 12px; align-items: center; }

.tf-warn { display: flex; gap: 12px; align-items: flex-start; background: var(--error-bg); border: 1px solid #FECACA; border-radius: 16px; padding: 16px; margin-top: 6px; }
.tf-warn svg { color: var(--error); flex-shrink: 0; margin-top: 1px; }
.tf-warn .tw-title { font-weight: 800; font-size: .9rem; color: var(--error); margin-bottom: 3px; }
.tf-warn .tw-desc { font-size: .8rem; color: #8a4040; line-height: 1.5; }

.tf-alert { font-size: .82rem; border-radius: 10px; padding: 10px 12px; margin-bottom: 12px; background: var(--error-bg); border: 1px solid #FECACA; color: #B91C1C; }
</style>

<div class="tf-wrap">

  <div class="sub-topbar">
    <div class="sub-topbar-left">
      <a href="security.php" class="sub-back" aria-label="Back" onclick="return goBack(event)">
        <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M19 12H5m0 0l7 7M5 12l7-7"/></svg>
      </a>
      <span class="sub-title">Security &amp; Privacy</span>
    </div>
    <a href="help_center.php" class="icon-btn" title="Help">
      <svg viewBox="0 0 24 24" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M9.09 9a3 3 0 115.83 1c0 2-3 2-3 4"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>
    </a>
  </div>

  <div class="tf-hero">
    <div class="tf-hero-icon">
      <svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/><polyline points="9 12 11 14 15 10"/></svg>
    </div>
    <h1>Two-Factor Authentication</h1>
    <p>Add an extra layer of security to your Dabil wallet.</p>
  </div>

  <?php if (!$has_2fa): ?>
  <div class="alert alert-info" style="margin-bottom:16px">
    <svg viewBox="0 0 24 24" stroke-width="2" stroke-linecap="round"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4M12 8h.01"/></svg>
    <span>Two-factor isn't available on this server yet — run <code>schema_customer_settings.sql</code> to enable it.</span>
  </div>
  <?php endif; ?>

  <!-- Email authentication -->
  <div class="tf-card">
    <form method="POST" id="toggleForm">
      <input type="hidden" name="action" value="toggle">
      <div class="tf-card-row">
        <span class="tf-ic"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 4h16a2 2 0 012 2v12a2 2 0 01-2 2H4a2 2 0 01-2-2V6a2 2 0 012-2z"/><polyline points="22 6 12 13 2 6"/></svg></span>
        <span class="tf-meta">
          <span class="tf-title">Email Authentication</span>
          <span class="tf-sub"><?php echo htmlspecialchars($masked_email); ?></span>
        </span>
        <label class="toggle-switch">
          <input type="checkbox" onchange="document.getElementById('toggleForm').submit()" <?php echo $twofa_on ? 'checked' : ''; ?> <?php echo $has_2fa ? '' : 'disabled'; ?>>
          <span class="toggle-slider"></span>
        </label>
      </div>
    </form>
    <div class="tf-hint">Recommended for basic protection. A one-time code is sent to your verified email each time you sign in on a new device.</div>
  </div>

  <!-- Authenticator app (TOTP) -->
  <div class="tf-card" id="auth">
    <div class="tf-card-row">
      <span class="tf-ic <?php echo $totp_on ? 'green' : 'muted'; ?>"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><line x1="14" y1="14" x2="21" y2="14"/><line x1="14" y1="18" x2="21" y2="18"/><line x1="17" y1="14" x2="17" y2="21"/></svg></span>
      <span class="tf-meta">
        <span class="tf-title">Authenticator App</span>
        <span class="tf-sub">Google Authenticator or Authy</span>
      </span>
      <?php if (!$has_totp): ?>
        <span class="tf-pill">Coming soon</span>
      <?php elseif ($totp_on): ?>
        <form method="POST"><input type="hidden" name="action" value="totp_disable"><button class="tf-btn danger" type="submit">Remove</button></form>
      <?php elseif (!$pending): ?>
        <form method="POST"><input type="hidden" name="action" value="totp_init"><button class="tf-btn" type="submit">Setup</button></form>
      <?php endif; ?>
    </div>

    <?php if ($has_totp && $totp_on): ?>
      <div class="tf-hint info"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4M12 8h.01"/></svg><span>Authenticator app is active — highly secure and recommended by security experts.</span></div>
    <?php elseif ($has_totp && $pending): ?>
      <div class="tf-setup">
        <?php if ($totp_error): ?><div class="tf-alert"><?php echo htmlspecialchars($totp_error); ?></div><?php endif; ?>
        <ol>
          <li>Open Google Authenticator or Authy.</li>
          <li>Scan the QR code below (or enter the key manually).</li>
          <li>Enter the 6-digit code it shows to confirm.</li>
        </ol>
        <div class="tf-qr" id="qr" data-otpauth="<?php echo htmlspecialchars($otpauth, ENT_QUOTES); ?>"></div>
        <div class="tf-key">Manual key<br><code><?php echo htmlspecialchars($pending); ?></code></div>
        <form method="POST">
          <input type="hidden" name="action" value="totp_verify">
          <input class="tf-code-input" type="text" name="code" inputmode="numeric" pattern="[0-9]*" maxlength="6" placeholder="000000" autocomplete="one-time-code" required>
          <div class="tf-setup-actions">
            <button class="tf-cancel" type="submit" formnovalidate name="action" value="totp_cancel">Cancel</button>
            <button class="tf-verify" type="submit">Verify &amp; Enable</button>
          </div>
        </form>
      </div>
    <?php else: ?>
      <div class="tf-hint info"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4M12 8h.01"/></svg><span>Highly secure — recommended by security experts. Works even without internet.</span></div>
    <?php endif; ?>
  </div>

  <!-- Backup codes -->
  <?php if ($has_2fa && ($twofa_on || $totp_on || $codes_remaining > 0)): ?>
  <div class="tf-card">
    <div class="tf-card-row">
      <span class="tf-ic muted"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="7.5" cy="15.5" r="4.5"/><path d="M10.7 12.3L20 3M16 7l3 3M14 9l2 2"/></svg></span>
      <span class="tf-meta">
        <span class="tf-title">Backup Codes</span>
        <span class="tf-sub"><?php echo $codes_remaining; ?> code<?php echo $codes_remaining === 1 ? '' : 's'; ?> remaining</span>
      </span>
      <form method="POST"><input type="hidden" name="action" value="regen"><button class="tf-btn ghost" type="submit"><?php echo $codes_remaining ? 'Regenerate' : 'Generate'; ?></button></form>
    </div>
    <?php if ($flash_codes): ?>
      <div class="tf-codes"><?php foreach ($flash_codes as $fc): ?><code><?php echo htmlspecialchars($fc); ?></code><?php endforeach; ?></div>
      <div class="tf-codes-actions">
        <button class="tf-btn" type="button" onclick="copyCodes()">Copy codes</button>
        <span class="tf-sub">Save these now — they won't be shown again.</span>
      </div>
      <textarea id="codeBlob" style="position:absolute;left:-9999px"><?php echo htmlspecialchars(implode("\n", $flash_codes)); ?></textarea>
    <?php else: ?>
      <div class="tf-hint">Each backup code can be used once if you can't reach your email or authenticator. Regenerating replaces any old codes.</div>
    <?php endif; ?>
  </div>
  <?php endif; ?>

  <div class="tf-warn">
    <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>
    <div>
      <div class="tw-title">Important Security Note</div>
      <div class="tw-desc">If you lose access to your authentication methods and your backup codes, you may be locked out of your Dabil wallet. Store your backup codes somewhere safe.</div>
    </div>
  </div>
</div>

<div class="os-toast" id="tfToast" style="position:fixed;bottom:calc(env(safe-area-inset-bottom) + 80px);left:50%;transform:translateX(-50%);background:#0F172A;color:#fff;padding:10px 18px;border-radius:30px;font-size:.8rem;font-weight:600;box-shadow:0 6px 20px rgba(0,0,0,.25);z-index:700;opacity:0;pointer-events:none;transition:opacity .25s"></div>

<?php if ($pending && !$totp_on): ?>
<script src="https://cdnjs.cloudflare.com/ajax/libs/qrcodejs/1.0.0/qrcode.min.js"></script>
<?php endif; ?>
<script>
function copyCodes(){
  const el = document.getElementById('codeBlob'); if (!el) return;
  el.select();
  navigator.clipboard.writeText(el.value).then(()=>tfToast('Backup codes copied')).catch(()=>{try{document.execCommand('copy');tfToast('Backup codes copied');}catch(e){tfToast('Copy failed');}});
}
function tfToast(m){const t=document.getElementById('tfToast');t.textContent=m;t.style.opacity='1';clearTimeout(window._tf);window._tf=setTimeout(()=>t.style.opacity='0',2000);}

(function(){
  const qr = document.getElementById('qr');
  if (qr && qr.dataset.otpauth && window.QRCode) {
    new QRCode(qr, { text: qr.dataset.otpauth, width: 148, height: 148, correctLevel: QRCode.CorrectLevel.M });
  } else if (qr && qr.dataset.otpauth) {
    qr.innerHTML = '<span style="font-size:.74rem;color:var(--text-muted);text-align:center">Use the manual key below in your authenticator app.</span>';
  }
})();
</script>

<?php include("includes/footer.php"); ?>
