<?php
// /admin/reset.php
// Validates token (scoped to organisation + company), updates the user's password_hash,
// and marks the token as used.

session_start();

$config = require __DIR__ . '/../lib/config.php';
require __DIR__ . '/../lib/db.php';

$base         = rtrim($config['base_url'] ?? '', '/');
$authCfg      = $config['auth'] ?? [];
$minLen       = (int)($authCfg['min_password_length']      ?? 8);
$allowEntraPw = (bool)($authCfg['allow_fallback_for_entra'] ?? false);

$orgFromHost = null;
$orgLogoUrl  = '';
$pageTitle   = 'Reset password — Admin';

if ($pdo instanceof PDO) {
  $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

  // Detect organisation from subdomain: {slug}.towlens.net etc.
  $host = $_SERVER['HTTP_HOST'] ?? '';
  $hostSlug = '';

  if ($host) {
    $parts = explode('.', $host);
    if (count($parts) >= 3) {
      $hostSlug = strtolower($parts[0]); // "client" in client.towlens.net
    }
  }

  if ($hostSlug !== '') {
    $stmt = $pdo->prepare("
      SELECT id, name, slug, logo_url
      FROM organisations
      WHERE slug = ?
      LIMIT 1
    ");
    $stmt->execute([$hostSlug]);
    $orgFromHost = $stmt->fetch(PDO::FETCH_ASSOC) ?: null;

    if ($orgFromHost) {
      $orgLogoUrl = trim((string)($orgFromHost['logo_url'] ?? ''));
      $pageTitle  = $orgFromHost['name'] . ' — Reset password';
    }
  }

  /* Ensure password_resets table exists (with org+company columns) */
  $pdo->exec("
    CREATE TABLE IF NOT EXISTS password_resets (
      id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
      user_id INT UNSIGNED NOT NULL,
      organisation_id INT UNSIGNED DEFAULT NULL,
      company_id INT UNSIGNED DEFAULT NULL,
      token_hash CHAR(64) NOT NULL,
      expires_at DATETIME NOT NULL,
      used_at DATETIME DEFAULT NULL,
      created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
      INDEX ix_token_hash (token_hash),
      INDEX ix_pw_org (organisation_id),
      INDEX ix_pw_company (company_id),
      CONSTRAINT fk_pw_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
  ");
  try {
    $pdo->exec("
      ALTER TABLE password_resets
      ADD CONSTRAINT fk_pwreset_org FOREIGN KEY (organisation_id)
      REFERENCES organisations(id) ON DELETE RESTRICT
    ");
  } catch (Throwable $e) {}
  try {
    $pdo->exec("
      ALTER TABLE password_resets
      ADD CONSTRAINT fk_pwreset_company FOREIGN KEY (company_id)
      REFERENCES companies(id) ON DELETE RESTRICT
    ");
  } catch (Throwable $e) {}
}

/* CSRF */
function csrf_token(): string {
  if (empty($_SESSION['csrf_reset'])) {
    $_SESSION['csrf_reset'] = bin2hex(random_bytes(16));
  }
  return $_SESSION['csrf_reset'];
}
function csrf_ok(): bool {
  return !empty($_POST['csrf']) && hash_equals($_SESSION['csrf_reset'] ?? '', $_POST['csrf']);
}

$token = trim($_GET['token'] ?? '');
$valid = false;
$err   = '';
$done  = false;
$row   = null;

if ($pdo instanceof PDO && $token !== '') {
  $hash = hash('sha256', $token);
  $stmt = $pdo->prepare("
    SELECT pr.id, pr.user_id, pr.organisation_id, pr.company_id, pr.expires_at, pr.used_at,
           u.email, u.provider
    FROM password_resets pr
    JOIN users u ON u.id = pr.user_id
    WHERE pr.token_hash = ? AND pr.used_at IS NULL AND pr.expires_at > NOW()
    LIMIT 1
  ");
  $stmt->execute([$hash]);
  $row = $stmt->fetch(PDO::FETCH_ASSOC);

  if ($row) {
    $prov = strtolower($row['provider'] ?? 'local');
    if ($prov === 'local' || ($prov === 'entra' && $allowEntraPw)) {
      $valid = true;
    } else {
      $err = 'This account uses single sign-on. Password reset is disabled.';
    }
  } else {
    $err = 'Invalid or expired link.';
  }
} else {
  $err = 'Invalid or expired link.';
}

if ($valid && $_SERVER['REQUEST_METHOD'] === 'POST' && $pdo instanceof PDO) {
  if (!csrf_ok()) {
    $err = 'Your session expired. Please try again.';
  } else {
    $p1 = (string)($_POST['password']  ?? '');
    $p2 = (string)($_POST['password2'] ?? '');
    if ($p1 === '' || $p2 === '') {
      $err = 'Please enter your new password twice.';
    } elseif ($p1 !== $p2) {
      $err = 'Passwords do not match.';
    } elseif (strlen($p1) < $minLen) {
      $err = "Password must be at least {$minLen} characters.";
    } else {
      // Re-check token row (fresh)
      $stmt = $pdo->prepare("
        SELECT pr.id, pr.user_id, pr.organisation_id, pr.company_id, pr.expires_at, pr.used_at,
               u.provider
        FROM password_resets pr
        JOIN users u ON u.id = pr.user_id
        WHERE pr.token_hash = ? AND pr.used_at IS NULL AND pr.expires_at > NOW()
        LIMIT 1
      ");
      $stmt->execute([hash('sha256', $token)]);
      $row = $stmt->fetch(PDO::FETCH_ASSOC);

      if ($row) {
        $hash = password_hash($p1, PASSWORD_DEFAULT);

        // Update the specific user (scoped by org+company to be extra safe)
        $pdo->prepare("
          UPDATE users
          SET password_hash=?
          WHERE id=? AND organisation_id=? AND company_id=?
        ")->execute([
          $hash,
          (int)$row['user_id'],
          (int)$row['organisation_id'],
          (int)$row['company_id'],
        ]);

        // Mark token used
        $pdo->prepare("
          UPDATE password_resets
          SET used_at=NOW()
          WHERE id=?
        ")->execute([(int)$row['id']]);

        $done  = true;
        $valid = false;
      } else {
        $err = 'Invalid or expired link.';
      }
    }
  }
}
?>
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title><?= htmlspecialchars($pageTitle) ?></title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <style>
    :root{
      --bg:#eceff3;
      --win:#ffffff;
      --ink:#1f2933;
      --muted:#5d6b78;
      --line:#cfd6de;
      --brand:#2f6db2;
      --brand-soft:#e0ecfb;
      --danger-bg:#fae7e7;
      --danger-border:#e3b1b1;
      --danger-text:#7f2020;
      --success-bg:#e6f4ea;
      --success-border:#b7e1c0;
      --success-text:#1e6b35;
      --radius:6px;
      --shadow-soft:0 6px 14px rgba(15,23,42,.08);
      --hdr:linear-gradient(#f8fafc,#e8edf3);
    }
    *{box-sizing:border-box;margin:0;padding:0}
    html,body{height:100%}
    body{
      margin:0;
      font:13px/1.45 "Segoe UI",Tahoma,Arial,sans-serif;
      color:var(--ink);
      background:
        radial-gradient(circle at top left,rgba(47,109,178,0.12),transparent),
        radial-gradient(circle at bottom right,rgba(148,163,253,0.1),transparent),
        var(--bg);
      -webkit-user-select:none;
      -moz-user-select:none;
      -ms-user-select:none;
      user-select:none;
    }
    .shell{
      min-height:100vh;
      display:flex;
      align-items:center;
      justify-content:center;
      padding:24px;
    }
    .window{
      width:min(720px,92vw);
      background:var(--win);
      border:1px solid var(--line);
      border-radius:var(--radius);
      box-shadow:var(--shadow-soft);
      overflow:hidden;
    }
    .ribbon{
      background:var(--hdr);
      border-bottom:1px solid var(--line);
      padding:10px 16px;
      display:flex;
      justify-content:space-between;
      align-items:center;
      gap:12px;
    }
    .ribbon-left{
      display:flex;
      align-items:center;
      gap:10px;
    }
    .org-logo{
      height:56px;
      max-width:220px;
      object-fit:contain;
      display:block;
      -webkit-user-drag:none;
      user-select:none;
      pointer-events:none;
    }
    @media (max-width:480px){
      .org-logo{
        height:42px;
        max-width:180px;
      }
    }
    .ribbon-icon{
      width:16px;
      height:16px;
      border-radius:3px;
      background:linear-gradient(145deg,var(--brand),#4f8ad1);
      box-shadow:0 1px 2px rgba(0,0,0,.18) inset;
      position:relative;
    }
    .ribbon-icon::before,
    .ribbon-icon::after{
      content:"";
      position:absolute;
      inset:4px 3px;
      border-radius:2px;
      border:1px solid rgba(255,255,255,.7);
    }
    .ribbon-title{
      display:flex;
      flex-direction:column;
    }
    .ribbon-title h1{
      font-size:16px;
      font-weight:600;
      margin:0;
      color:#111827;
    }
    .ribbon-sub{
      font-size:11px;
      color:var(--muted);
    }
    .chip{
      background:#eff6ff;
      border:1px solid #bfdbfe;
      color:#1d4ed8;
      border-radius:999px;
      padding:2px 9px;
      font-size:10px;
      font-weight:600;
      text-transform:uppercase;
      letter-spacing:.06em;
    }
    .body{
      padding:16px 18px 18px;
    }
    .alert{
      padding:9px 10px;
      border-radius:4px;
      background:var(--danger-bg);
      border:1px solid var(--danger-border);
      color:var(--danger-text);
      margin:0 0 8px;
      font-size:12px;
    }
    .note{
      padding:9px 10px;
      border-radius:4px;
      background:var(--success-bg);
      border:1px solid var(--success-border);
      color:var(--success-text);
      margin:0 0 8px;
      font-size:12px;
    }
    .muted{
      color:var(--muted);
      margin-bottom:8px;
    }
    .stack{
      display:flex;
      flex-direction:column;
      gap:4px;
      margin:8px 0 6px;
    }
    input[type=password]{
      padding:8px 9px;
      border:1px solid #cfd6de;
      border-radius:4px;
      width:100%;
      font-size:13px;
      background:#f9fafb;
      transition:border-color .18s,box-shadow .18s,background-color .18s;
      -webkit-user-select:text;
      -moz-user-select:text;
      -ms-user-select:text;
      user-select:text;
    }
    input[type=password]:focus{
      outline:none;
      border-color:var(--brand);
      background:#ffffff;
      box-shadow:0 0 0 1px var(--brand-soft),0 0 0 3px rgba(47,109,178,0.14);
    }
    .btn{
      appearance:none;
      border:1px solid #bfc8d2;
      background:linear-gradient(#f8fafc,#e6ecf2);
      padding:8px 12px;
      border-radius:4px;
      cursor:pointer;
      font-weight:600;
      font-size:13px;
      display:inline-flex;
      align-items:center;
      justify-content:center;
      gap:6px;
      transition:all .16s ease-out;
      -webkit-user-select:none;
      -moz-user-select:none;
      -ms-user-select:none;
      user-select:none;
      text-decoration:none;
      color:var(--ink);
    }
    .btn:hover{
      background:linear-gradient(#ffffff,#e2e8f0);
      box-shadow:0 1px 3px rgba(0,0,0,.12);
    }
    .btn:active{
      transform:translateY(1px);
      box-shadow:none;
    }
    .btn.primary{
      border-color:#2a5f9c;
      color:#ffffff;
      background:linear-gradient(#3b79c1,#255b94);
      box-shadow:0 2px 4px rgba(37,91,148,.35);
    }
    .btn.primary:hover{
      background:linear-gradient(#4b82c7,#24558b);
    }
    .actions{
      display:flex;
      flex-wrap:wrap;
      gap:8px;
      margin-top:8px;
    }
    button,input,select,textarea,a{
      -webkit-user-select:auto;
      -moz-user-select:auto;
      -ms-user-select:auto;
      user-select:auto;
    }
  </style>
</head>
<body>
  <div class="shell">
    <main class="window">
      <div class="ribbon">
        <div class="ribbon-left">
          <?php if ($orgLogoUrl): ?>
            <img src="<?= htmlspecialchars($orgLogoUrl) ?>"
                 alt="<?= htmlspecialchars($orgFromHost['name'] ?? 'Logo') ?>"
                 class="org-logo"
                 draggable="false">
          <?php else: ?>
            <div class="ribbon-icon" aria-hidden="true"></div>
          <?php endif; ?>
          <div class="ribbon-title">
            <h1><?= htmlspecialchars($orgFromHost['name'] ?? 'Reset password') ?></h1>
            <div class="ribbon-sub">Set a new password for your admin access</div>
          </div>
        </div>
        <div class="chip">ADMIN PORTAL</div>
      </div>

      <div class="body">
        <?php if ($done): ?>
          <div class="note">
            Your password has been updated.
            You can now
            <a href="<?= htmlspecialchars($base) ?>/admin/login.php">sign in</a>.
          </div>
        <?php elseif (!$valid): ?>
          <div class="alert"><?= htmlspecialchars($err ?: 'Invalid or expired link.') ?></div>
        <?php else: ?>
          <?php if ($err): ?>
            <div class="alert"><?= htmlspecialchars($err) ?></div>
          <?php endif; ?>

          <p class="muted">
            Choose a strong password of at least <?= (int)$minLen ?> characters.
          </p>

          <form method="post" action="" autocomplete="off" novalidate>
            <input type="hidden" name="csrf" value="<?= htmlspecialchars(csrf_token()) ?>">

            <div class="stack">
              <input type="password"
                     name="password"
                     placeholder="New password"
                     required>
            </div>

            <div class="stack">
              <input type="password"
                     name="password2"
                     placeholder="Confirm new password"
                     required>
            </div>

            <div class="actions">
              <button class="btn primary" type="submit">
                <span>Set new password</span>
              </button>
              <button class="btn" type="button"
                      data-href="<?= htmlspecialchars($base) ?>/admin/login.php">
                <span>Back to sign in</span>
              </button>
            </div>
          </form>
        <?php endif; ?>
      </div>
    </main>
  </div>

  <script>
    // JS navigation for back button so no URL preview on hover
    document.addEventListener('click', function(e){
      var btn = e.target.closest('button[data-href]');
      if (!btn) return;
      e.preventDefault();
      var url = btn.getAttribute('data-href');
      if (url) window.location.assign(url);
    });

    // Block right-click
    window.addEventListener('contextmenu', function(e){
      e.preventDefault();
    }, {capture:true});

    // Prevent selection drag outside interactive elements
    window.addEventListener('mousedown', function(e){
      var t = e.target;
      if (
        t.tagName === 'INPUT' ||
        t.tagName === 'BUTTON' ||
        t.tagName === 'SELECT' ||
        t.tagName === 'TEXTAREA' ||
        t.tagName === 'A'
      ) {
        return;
      }
      if (window.getSelection) {
        var sel = window.getSelection();
        if (sel && sel.removeAllRanges) sel.removeAllRanges();
      }
    });
  </script>
</body>
</html>

