<?php
// ════════════════════════════════════════════════════════════════
//  SECURE ADMIN PANEL  —  server-side session auth
//  No password is ever sent to or visible in the browser.
// ════════════════════════════════════════════════════════════════

// ── Session hardening ────────────────────────────────────────────
session_start([
    'cookie_httponly'  => true,
    'cookie_samesite'  => 'Strict',
    'use_strict_mode'  => true,
    'gc_maxlifetime'   => 3600,          // 1-hour session lifetime
]);

// ── Security headers ─────────────────────────────────────────────
header('X-Content-Type-Options: nosniff');
header('X-Frame-Options: DENY');
header('X-XSS-Protection: 1; mode=block');
header('Referrer-Policy: no-referrer');
header('Cache-Control: no-store, no-cache, must-revalidate, private');
header('Pragma: no-cache');

// ════════════════════════════════════════════════════════════════
//  ⚠  CHANGE THIS — only ever lives on the server, never in browser
// ════════════════════════════════════════════════════════════════
define('ADMIN_PASSWORD',    'Jio@Admin2024!');   // ← set your password here
define('MAX_ATTEMPTS',      5);                   // failed logins before lockout
define('LOCKOUT_SECONDS',   300);                 // lockout duration (5 min)
define('SESSION_TIMEOUT',   3600);                // auto-logout after 1 hour

define('CONFIG_FILE', __DIR__ . '/data/info.json');
define('CONFIG_DIR',  __DIR__ . '/data');

// ── CSRF token ───────────────────────────────────────────────────
if (empty($_SESSION['csrf'])) {
    $_SESSION['csrf'] = bin2hex(random_bytes(32));
}
$csrf = $_SESSION['csrf'];

// ── Rate limiting helpers ─────────────────────────────────────────
function isLockedOut(): bool {
    if (empty($_SESSION['fail_count']) || $_SESSION['fail_count'] < MAX_ATTEMPTS) return false;
    $elapsed = time() - ($_SESSION['fail_time'] ?? 0);
    if ($elapsed >= LOCKOUT_SECONDS) { $_SESSION['fail_count'] = 0; return false; }
    return true;
}
function recordFailure(): void {
    $_SESSION['fail_count'] = ($_SESSION['fail_count'] ?? 0) + 1;
    $_SESSION['fail_time']  = time();
}
function remainingLockout(): int {
    return max(0, LOCKOUT_SECONDS - (time() - ($_SESSION['fail_time'] ?? 0)));
}

// ── Session timeout check ─────────────────────────────────────────
function sessionExpired(): bool {
    if (empty($_SESSION['auth_time'])) return false;
    return (time() - $_SESSION['auth_time']) > SESSION_TIMEOUT;
}

// ── Process POST ──────────────────────────────────────────────────
$error      = '';
$saveMsg    = '';
$saveMsgType = 'success';
$timeoutMsg = isset($_GET['timeout']) ? 'Session expired. Please log in again.' : '';

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $action    = $_POST['action'] ?? '';
    $postCsrf  = $_POST['csrf']   ?? '';

    // CSRF validation for every POST
    if (!hash_equals($csrf, $postCsrf)) {
        $error = 'Invalid request token. Please refresh and try again.';
    } else {

        // ── LOGIN ─────────────────────────────────────────────────
        if ($action === 'login') {
            if (isLockedOut()) {
                $mins  = ceil(remainingLockout() / 60);
                $error = "Too many failed attempts. Try again in {$mins} minute(s).";
            } elseif (hash_equals(ADMIN_PASSWORD, $_POST['password'] ?? '')) {
                // Regenerate session ID on privilege escalation
                session_regenerate_id(true);
                $_SESSION['authenticated'] = true;
                $_SESSION['auth_time']     = time();
                $_SESSION['fail_count']    = 0;
                $_SESSION['csrf']          = bin2hex(random_bytes(32)); // fresh CSRF
                header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?'));
                exit;
            } else {
                recordFailure();
                $remaining = MAX_ATTEMPTS - ($_SESSION['fail_count'] ?? 0);
                $error = $remaining > 0
                    ? "Incorrect password. {$remaining} attempt(s) remaining."
                    : 'Account locked for ' . ceil(LOCKOUT_SECONDS / 60) . ' minutes.';
            }

        // ── LOGOUT ────────────────────────────────────────────────
        } elseif ($action === 'logout') {
            $_SESSION = [];
            session_destroy();
            header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?'));
            exit;

        // ── SAVE CONFIG ───────────────────────────────────────────
        } elseif ($action === 'save' && !empty($_SESSION['authenticated'])) {
            if (sessionExpired()) {
                $_SESSION = []; session_destroy();
                header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?') . '?timeout=1');
                exit;
            }
            $primary = trim($_POST['upi_primary'] ?? '');
            $paytm   = trim($_POST['upi_paytm']   ?? '');

            if (!$primary || !$paytm) {
                $saveMsg = 'Both UPI IDs are required.'; $saveMsgType = 'error';
            } elseif (!str_contains($primary, '@') || !str_contains($paytm, '@')) {
                $saveMsg = 'Invalid UPI ID — must contain @.'; $saveMsgType = 'error';
            } elseif (preg_match('/[<>\'";&]/', $primary . $paytm)) {
                $saveMsg = 'Invalid characters in UPI ID.'; $saveMsgType = 'error';
            } else {
                if (!is_dir(CONFIG_DIR)) mkdir(CONFIG_DIR, 0755, true);
                $payload = json_encode(
                    ['name' => $primary, 'email' => $paytm],
                    JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE
                );
                if (file_put_contents(CONFIG_FILE, $payload, LOCK_EX) !== false) {
                    $saveMsg = '✅ Config saved successfully.';
                } else {
                    $saveMsg = '❌ Write failed — check folder permissions on /data/'; $saveMsgType = 'error';
                }
            }

        // ── CHANGE PASSWORD ───────────────────────────────────────
        } elseif ($action === 'change_password' && !empty($_SESSION['authenticated'])) {
            $oldPass  = $_POST['old_password']  ?? '';
            $newPass  = $_POST['new_password']  ?? '';
            $newPass2 = $_POST['new_password2'] ?? '';

            if (!hash_equals(ADMIN_PASSWORD, $oldPass)) {
                $saveMsg = '❌ Current password is incorrect.'; $saveMsgType = 'error';
            } elseif (strlen($newPass) < 8) {
                $saveMsg = '❌ New password must be at least 8 characters.'; $saveMsgType = 'error';
            } elseif (!hash_equals($newPass, $newPass2)) {
                $saveMsg = '❌ New passwords do not match.'; $saveMsgType = 'error';
            } else {
                // Write new password back to this file
                $thisFile = __FILE__;
                $src      = file_get_contents($thisFile);
                $escaped  = addslashes($newPass);
                $updated  = preg_replace(
                    "/define\('ADMIN_PASSWORD',\s*'[^']+'\)/",
                    "define('ADMIN_PASSWORD',    '{$escaped}')",
                    $src
                );
                if ($updated && file_put_contents($thisFile, $updated, LOCK_EX) !== false) {
                    $saveMsg = '✅ Password changed. Please log in again.';
                    $_SESSION = []; session_destroy();
                    header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?') . '?changed=1');
                    exit;
                } else {
                    $saveMsg = '❌ Could not update password — check file permissions.'; $saveMsgType = 'error';
                }
            }
        }
    }
}

$isAuth = !empty($_SESSION['authenticated']) && !sessionExpired();

// Read current config for display
$cfg = ['name' => '', 'email' => ''];
if ($isAuth && file_exists(CONFIG_FILE)) {
    $read = json_decode(file_get_contents(CONFIG_FILE), true);
    if ($read) $cfg = $read;
}

$passwordChanged = isset($_GET['changed']);
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Admin Panel – UPI Config</title>
<style>
    *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
    :root {
        --bg:      #0a0f1e;
        --surface: #111827;
        --surf2:   #1a2235;
        --border:  rgba(255,255,255,0.08);
        --accent:  #4f7df4;
        --accent2: #7c3aed;
        --ok:      #10b981;
        --err:     #ef4444;
        --warn:    #f59e0b;
        --text:    #f1f5f9;
        --muted:   #94a3b8;
    }
    body {
        font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
        background: var(--bg); color: var(--text);
        min-height: 100vh; display: flex;
        align-items: center; justify-content: center; padding: 1rem;
    }
    input[type=password], input[type=text] {
        width: 100%; background: var(--surf2); border: 1px solid var(--border);
        border-radius: 0.65rem; color: var(--text); font-family: inherit;
        font-size: 0.9rem; padding: 0.7rem 0.9rem; outline: none;
        transition: border-color 0.2s, box-shadow 0.2s; margin-bottom: 1rem;
    }
    input:focus { border-color: var(--accent); box-shadow: 0 0 0 3px rgba(79,125,244,0.15); }
    label { display: block; font-size: 0.75rem; font-weight: 700; color: var(--muted);
            text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 0.35rem; }
    /* ── Buttons ── */
    .btn { width: 100%; border: none; border-radius: 0.75rem; font-family: inherit;
           font-size: 0.9rem; font-weight: 700; padding: 0.8rem; cursor: pointer;
           transition: opacity 0.2s, transform 0.15s; letter-spacing: 0.02em; }
    .btn:hover  { opacity: 0.9; transform: translateY(-1px); }
    .btn:active { transform: scale(0.98); }
    .btn-primary { background: linear-gradient(135deg, var(--accent), var(--accent2)); color: #fff; }
    .btn-green   { background: linear-gradient(135deg, var(--ok), #059669); color: #fff; }
    .btn-sm      { width: auto; padding: 0.4rem 0.9rem; font-size: 0.8rem; border-radius: 0.6rem; }
    .btn-logout  { background: rgba(239,68,68,0.12); color: var(--err);
                   border: 1px solid rgba(239,68,68,0.25); }
    /* ── Cards ── */
    .card { background: var(--surface); border: 1px solid var(--border);
            border-radius: 1.25rem; padding: 1.5rem; margin-bottom: 1rem; }
    .wrap { width: 100%; max-width: 520px; }
    .login-wrap { width: 100%; max-width: 400px; }
    /* ── Login card ── */
    .login-card { background: var(--surface); border: 1px solid var(--border);
                  border-radius: 1.5rem; padding: 2.5rem 2rem;
                  box-shadow: 0 25px 60px rgba(0,0,0,0.6); }
    .brand { display: flex; align-items: center; gap: 0.6rem;
             justify-content: center; margin-bottom: 2rem; }
    .brand-dot { width: 10px; height: 10px; border-radius: 50%;
                 background: linear-gradient(135deg, var(--accent), var(--accent2)); }
    .brand-name { font-size: 1.1rem; font-weight: 700; }
    .login-title { font-size: 1.6rem; font-weight: 800; text-align: center;
                   letter-spacing: -0.03em; margin-bottom: 0.3rem; }
    .login-sub   { text-align: center; color: var(--muted); font-size: 0.875rem; margin-bottom: 2rem; }
    /* ── Alerts ── */
    .alert { border-radius: 0.65rem; padding: 0.75rem 1rem; font-size: 0.85rem;
             font-weight: 600; margin-bottom: 1rem; border: 1px solid; }
    .alert-err  { background: rgba(239,68,68,0.1);  color: var(--err);  border-color: rgba(239,68,68,0.3); }
    .alert-ok   { background: rgba(16,185,129,0.1); color: var(--ok);   border-color: rgba(16,185,129,0.3); }
    .alert-warn { background: rgba(245,158,11,0.1); color: var(--warn); border-color: rgba(245,158,11,0.3); }
    /* ── Admin header ── */
    .admin-hdr { display: flex; align-items: center; justify-content: space-between; margin-bottom: 1.25rem; }
    .admin-title { font-size: 1.4rem; font-weight: 800; letter-spacing: -0.03em; }
    .badge { background: rgba(16,185,129,0.15); color: var(--ok);
             border: 1px solid rgba(16,185,129,0.3); border-radius: 999px;
             font-size: 0.72rem; font-weight: 700; padding: 0.25rem 0.6rem; }
    /* ── Card titles ── */
    .card-title { font-size: 0.8rem; font-weight: 700; color: var(--muted);
                  text-transform: uppercase; letter-spacing: 0.07em;
                  margin-bottom: 1.25rem; display: flex; align-items: center; gap: 0.5rem; }
    .hint { font-size: 0.72rem; color: var(--muted); margin-top: -0.7rem; margin-bottom: 1rem; display: block; }
    /* ── Config preview ── */
    .config-pre { background: var(--surf2); border: 1px solid var(--border); border-radius: 0.65rem;
                  padding: 1rem; font-family: monospace; font-size: 0.8rem; color: #7dd3fc;
                  white-space: pre-wrap; word-break: break-all; line-height: 1.6; }
    /* ── Security badge ── */
    .sec-info { display: flex; align-items: center; gap: 0.5rem;
                background: rgba(79,125,244,0.08); border: 1px solid rgba(79,125,244,0.2);
                border-radius: 0.6rem; padding: 0.6rem 0.9rem; font-size: 0.78rem;
                color: #93c5fd; margin-bottom: 1rem; }
    hr { border: none; border-top: 1px solid var(--border); margin: 1rem 0; }
    /* ── Attempt meter ── */
    .attempt-bar { height: 4px; border-radius: 2px; background: var(--surf2);
                   margin-top: 0.75rem; overflow: hidden; }
    .attempt-fill { height: 100%; border-radius: 2px;
                    background: linear-gradient(90deg, var(--ok), var(--err));
                    transition: width 0.3s; }
    /* ── Collapsible ── */
    details > summary { cursor: pointer; color: var(--muted); font-size: 0.8rem;
                        font-weight: 600; list-style: none; padding: 0.5rem 0; }
    details > summary::-webkit-details-marker { display: none; }
    details[open] > summary { color: var(--text); }
    details > div { padding-top: 0.75rem; }
</style>
</head>
<body>

<?php if ($passwordChanged): ?>
<script>/* redirect query cleaned */history.replaceState(null,'',location.pathname);</script>
<?php endif; ?>

<?php if (!$isAuth): ?>
<!-- ══════════════════ LOGIN SCREEN ══════════════════ -->
<div class="login-wrap">
    <div class="login-card">
        <div class="brand"><div class="brand-dot"></div><span class="brand-name">JioOnePay Admin</span></div>
        <h1 class="login-title">Secure Login</h1>
        <p class="login-sub">Authentication required to continue</p>

        <?php if ($timeoutMsg): ?>
            <div class="alert alert-warn">⏱ <?= htmlspecialchars($timeoutMsg) ?></div>
        <?php endif; ?>
        <?php if ($passwordChanged): ?>
            <div class="alert alert-ok">✅ Password updated. Please log in with your new password.</div>
        <?php endif; ?>
        <?php if ($error): ?>
            <div class="alert alert-err"><?= htmlspecialchars($error) ?></div>
        <?php endif; ?>

        <form method="POST" autocomplete="off">
            <input type="hidden" name="csrf"   value="<?= htmlspecialchars($csrf) ?>">
            <input type="hidden" name="action" value="login">
            <label for="pw">Password</label>
            <input type="password" id="pw" name="password" placeholder="••••••••"
                   autocomplete="current-password" autofocus required>
            <button type="submit" class="btn btn-primary">Login →</button>
        </form>

        <?php if (!empty($_SESSION['fail_count']) && $_SESSION['fail_count'] > 0): ?>
        <div class="attempt-bar" title="Failed attempts">
            <div class="attempt-fill"
                 style="width:<?= min(100, ($_SESSION['fail_count'] / MAX_ATTEMPTS) * 100) ?>%"></div>
        </div>
        <?php endif; ?>

        <p style="font-size:0.72rem;color:var(--muted);text-align:center;margin-top:1rem;">
            🔒 <?= MAX_ATTEMPTS ?> failed attempts trigger a <?= LOCKOUT_SECONDS/60 ?>-min lockout
        </p>
    </div>
</div>

<?php else: ?>
<!-- ══════════════════ ADMIN DASHBOARD ══════════════════ -->
<div class="wrap">
    <div class="admin-hdr">
        <div>
            <div class="admin-title">UPI Admin Panel</div>
        </div>
        <div style="display:flex;gap:0.6rem;align-items:center;">
            <span class="badge">● LIVE</span>
            <form method="POST" style="margin:0;">
                <input type="hidden" name="csrf"   value="<?= htmlspecialchars($csrf) ?>">
                <input type="hidden" name="action" value="logout">
                <button type="submit" class="btn btn-logout btn-sm">Logout</button>
            </form>
        </div>
    </div>

    <div class="sec-info">
        🔐 Server-side session authenticated &nbsp;·&nbsp;
        Auto-logout in <?= round((SESSION_TIMEOUT - (time() - $_SESSION['auth_time'])) / 60) ?> min
    </div>

    <?php if ($saveMsg): ?>
    <div class="alert alert-<?= $saveMsgType === 'error' ? 'err' : 'ok' ?>">
        <?= htmlspecialchars($saveMsg) ?>
    </div>
    <?php endif; ?>

    <!-- UPI Config Card -->
    <div class="card">
        <div class="card-title">
            <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
            UPI Configuration
        </div>
        <form method="POST">
            <input type="hidden" name="csrf"   value="<?= htmlspecialchars($csrf) ?>">
            <input type="hidden" name="action" value="save">

            <label for="upi1">Primary UPI ID <span style="color:var(--accent)">(PhonePe &amp; QR)</span></label>
            <input type="text" id="upi1" name="upi_primary"
                   value="<?= htmlspecialchars($cfg['name']) ?>"
                   placeholder="e.g. merchant@ybl" autocomplete="off">
            <span class="hint">Used for PhonePe deeplink and QR code.</span>

            <label for="upi2">Paytm UPI ID <span style="color:#00baf2">(Paytm specific)</span></label>
            <input type="text" id="upi2" name="upi_paytm"
                   value="<?= htmlspecialchars($cfg['email']) ?>"
                   placeholder="e.g. merchant@paytm" autocomplete="off">
            <span class="hint">Used only for Paytm deeplink.</span>

            <button type="submit" class="btn btn-green" style="margin-top:0.5rem;">
                💾 Save &amp; Apply Changes
            </button>
        </form>
    </div>

    <!-- Current Config Preview -->
    <div class="card">
        <div class="card-title">
            <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg>
            Current Stored Config
        </div>
        <div class="config-pre"><?= htmlspecialchars(
            file_exists(CONFIG_FILE)
                ? file_get_contents(CONFIG_FILE)
                : '⚠️ data/info.json not found — save config to create it.'
        ) ?></div>
    </div>

    <!-- Change Password Card -->
    <div class="card">
        <details>
            <summary>🔑 Change Admin Password</summary>
            <div>
                <form method="POST">
                    <input type="hidden" name="csrf"   value="<?= htmlspecialchars($csrf) ?>">
                    <input type="hidden" name="action" value="change_password">

                    <label for="oldpw">Current Password</label>
                    <input type="password" id="oldpw" name="old_password" placeholder="Current password" required>

                    <label for="newpw">New Password <span style="color:var(--muted)">(min 8 chars)</span></label>
                    <input type="password" id="newpw" name="new_password" placeholder="New password" required minlength="8">

                    <label for="newpw2">Confirm New Password</label>
                    <input type="password" id="newpw2" name="new_password2" placeholder="Repeat new password" required minlength="8">

                    <button type="submit" class="btn btn-primary" style="background:linear-gradient(135deg,#f59e0b,#d97706);">
                        🔐 Update Password
                    </button>
                </form>
            </div>
        </details>
    </div>

</div>
<?php endif; ?>

</body>
</html>
