<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title><?= $title ?? 'Dashboard' ?> — Job Portal</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.css">
    <style>
        :root {
            --li-blue: #0a66c2;
            --li-blue-dark: #004182;
            --li-blue-light: #e8f0fe;
            --li-bg: #f4f2ee;
            --li-text: #1d2226;
            --li-text-muted: #56687a;
            --li-border: #e0dfdc;
            --li-green: #057642;
            --li-red: #b74700;
        }
        * { box-sizing: border-box; }
        html, body { overflow-x: hidden; max-width: 100vw; }

        /* Self-contained responsive layout for the sidebar+content row —
           written in plain CSS (not relying on Bootstrap's flex-md-row
           utility class alone) so this still works even if the Bootstrap
           CDN stylesheet fails to load or is blocked by a browser
           extension. This is the actual layout-stacking mechanism;
           Bootstrap's own classes are a secondary reinforcement. */
        #panelLayoutRow { display: flex; flex-direction: row; align-items: flex-start; gap: 16px; width: 100%; }
        #mobileMenuToggleWrap { display: none; }
        @media (max-width: 767.98px) {
            #panelLayoutRow { flex-direction: column; }
            #panelMainContent { width: 100% !important; max-width: 100% !important; }
            #mobileSidebarCollapse { width: 100%; max-width: 100%; }
            #mobileSidebarCollapse:not(.show) { display: none; }
            #mobileMenuToggleWrap { display: block; }
        }
        @media (min-width: 768px) {
            #mobileSidebarCollapse { display: block !important; }
        }
        body {
            background: var(--li-bg);
            color: var(--li-text);
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
            font-size: 14px;
        }
        a { text-decoration: none; }

        /* Topbar */
        .li-topbar {
            background: #fff;
            border-bottom: 1px solid var(--li-border);
            height: 56px;
            position: sticky; top: 0; z-index: 1000;
            max-width: 100%;
        }
        .li-topbar .brand {
            color: var(--li-blue);
            font-weight: 800;
            font-size: 22px;
            letter-spacing: -0.5px;
        }
        .li-topbar .search-box {
            background: var(--li-bg);
            border-radius: 4px;
            border: none;
            padding: 8px 12px 8px 36px;
            font-size: 14px;
            width: 260px;
        }
        .li-search-wrap { position: relative; }
        .li-search-wrap i { position: absolute; left: 12px; top: 50%; transform: translateY(-50%); color: var(--li-text-muted); }
        .li-nav-icon {
            color: var(--li-text-muted);
            text-align: center;
            font-size: 12px;
            padding: 0 12px;
            position: relative;
        }
        .li-nav-icon i { font-size: 22px; display: block; }
        .li-nav-icon:hover { color: var(--li-text); }
        .li-nav-icon.active { color: var(--li-text); border-bottom: 2px solid var(--li-text); }
        .li-badge {
            position: absolute; top: -2px; right: 6px;
            background: #cc1016; color: #fff; border-radius: 50%;
            font-size: 10px; min-width: 16px; height: 16px; line-height: 16px;
            padding: 0 3px;
        }
        .avatar-circle {
            width: 32px; height: 32px; border-radius: 50%;
            background: var(--li-blue); color: #fff;
            display: inline-flex; align-items: center; justify-content: center;
            font-weight: 700; font-size: 13px;
        }
        .avatar-circle.lg { width: 72px; height: 72px; font-size: 26px; }
        .avatar-circle.md { width: 48px; height: 48px; font-size: 18px; }

        /* Sidebar */
        .li-sidebar {
            width: 240px;
            flex-shrink: 0;
        }
        .li-sidebar .card { border: 1px solid var(--li-border); box-shadow: none; }
        .li-nav-link {
            display: flex; align-items: center; gap: 12px;
            padding: 10px 16px;
            color: var(--li-text);
            font-weight: 600;
            font-size: 14px;
            border-radius: 4px;
        }
        .li-nav-link i { font-size: 18px; width: 20px; color: var(--li-text-muted); }
        .li-nav-link:hover { background: var(--li-bg); }
        .li-nav-link.active { background: var(--li-blue-light); color: var(--li-blue); }
        .li-nav-link.active i { color: var(--li-blue); }

        /* Cards */
        .li-card {
            background: #fff;
            border: 1px solid var(--li-border);
            border-radius: 8px;
        }
        .li-card-header {
            padding: 16px 20px;
            border-bottom: 1px solid var(--li-border);
            font-weight: 700;
            font-size: 16px;
        }
        .li-card-body { padding: 20px; }

        /* Buttons */
        .btn-li-primary {
            background: var(--li-blue); border-color: var(--li-blue); color: #fff;
            border-radius: 24px; font-weight: 600; padding: 6px 20px;
        }
        .btn-li-primary:hover { background: var(--li-blue-dark); border-color: var(--li-blue-dark); color: #fff; }
        .btn-li-outline {
            background: #fff; border: 1.5px solid var(--li-blue); color: var(--li-blue);
            border-radius: 24px; font-weight: 600; padding: 5px 20px;
        }
        .btn-li-outline:hover { background: var(--li-blue-light); color: var(--li-blue); }
        .btn-li-ghost {
            background: transparent; border: 1.5px solid var(--li-text-muted); color: var(--li-text);
            border-radius: 24px; font-weight: 600; padding: 5px 20px;
        }

        /* Badges/pills */
        .li-pill {
            display: inline-block; padding: 2px 10px; border-radius: 12px;
            font-size: 12px; font-weight: 600;
        }
        .li-pill-green { background: #e9f7ef; color: var(--li-green); }
        .li-pill-blue { background: var(--li-blue-light); color: var(--li-blue); }
        .li-pill-gray { background: #eef3f8; color: var(--li-text-muted); }
        .li-pill-red { background: #fbeae5; color: var(--li-red); }
        .li-pill-yellow { background: #fff8e1; color: #8a6d00; }

        .li-table th { color: var(--li-text-muted); font-weight: 600; font-size: 12px; text-transform: uppercase; letter-spacing: 0.5px; border-bottom: 1px solid var(--li-border); }
        .li-table td { border-bottom: 1px solid var(--li-border); vertical-align: middle; padding: 14px 8px; }

        .li-stat-num { font-size: 28px; font-weight: 800; color: var(--li-text); }
        .li-stat-label { color: var(--li-text-muted); font-size: 13px; }

        .toast-container { z-index: 2000; }

        /* ===== Mobile Responsive ===== */
        .mobile-sidebar-toggle { display: none; }

        @media (max-width: 767.98px) {
            body { font-size: 15px; }

            /* Topbar: icon-only, tighter spacing, no overflow */
            .li-topbar { height: 52px; padding-left: 10px !important; padding-right: 10px !important; }
            .li-topbar .brand { font-size: 18px; margin-right: 8px !important; }
            .li-nav-icon { padding: 0 6px; font-size: 10px; }
            .li-nav-icon i { font-size: 19px; }
            .li-nav-icon .nav-label { display: none; }
            #topbarCreditBalance { font-size: 11px; padding: 2px 6px; }
            #topbarCreditBalance .credit-label { display: none; }

            /* Sidebar becomes a collapsible drawer above the content */
            .mobile-sidebar-toggle { display: block; }
            #mobileSidebarCollapse { width: 100%; }
            .li-sidebar { width: 100% !important; }
            .li-sidebar .filter-section { max-height: none; }

            /* Content container gets no side padding waste */
            .container-fluid { padding-left: 12px !important; padding-right: 12px !important; }
            .li-card-body { padding: 14px !important; }
            .li-card-header { padding: 12px 14px !important; font-size: 15px; }

            /* Tables: allow horizontal scroll, never force page-wide overflow */
            .table-responsive { border: none; }
            .li-table th, .li-table td { white-space: nowrap; }

            /* Buttons in a row on mobile: let them wrap instead of overflowing */
            .btn-li-primary, .btn-li-outline, .btn-li-ghost { padding-left: 14px; padding-right: 14px; }

            /* Job/candidate card action columns: stack under the info instead of squeezing beside it */
            .job-card-actions-col { min-width: 100% !important; margin-top: 12px; text-align: left !important; }

            /* Messages: list and open thread take turns at full width
               instead of squeezing a 320px list beside a thread on a
               375px phone. JS toggles #convoListPanel/#threadPanel via
               d-none — these two rules just make sure the panel that IS
               shown actually fills the available width. */
            #convoListPanel:not(.d-none) { width: 100% !important; }
            #threadPanel.d-flex { width: 100%; }

            /* Modals: near-fullscreen on small phones so forms are usable */
            .modal-dialog { margin: 0.5rem; }

            h3 { font-size: 1.4rem; }
            h5 { font-size: 1.1rem; }
        }

        @media (max-width: 575.98px) {
            .li-stat-num { font-size: 22px; }
            .avatar-circle.lg { width: 56px; height: 56px; font-size: 20px; }

            /* Safety net: the "title left, meta/actions right" pattern is
               used throughout the site (job cards, candidate cards, list
               headers, modals). On very narrow phones, wrap instead of
               squeezing both sides into unreadable slivers. */
            .d-flex.justify-content-between:not(.flex-nowrap) { flex-wrap: wrap; gap: 8px; }

            /* Filter bars (ATS, Registered Users, Agencies, Payments, etc.)
               use several fixed-width <select>/<input> side by side in a
               d-flex gap-2 row — fine on desktop, but they don't fit a
               phone screen together. Let the row wrap and each field go
               full width so they stack cleanly instead of overflowing. */
            .d-flex.gap-2:not(.flex-nowrap), .d-flex.gap-3:not(.flex-nowrap) { flex-wrap: wrap; }
            .d-flex.gap-2 select[style*="width"], .d-flex.gap-3 select[style*="width"],
            .d-flex.gap-2 input[style*="width"], .d-flex.gap-3 input[style*="width"] {
                width: 100% !important;
            }
        }
    </style>
</head>
<body>

<nav class="li-topbar d-flex align-items-center px-3">
    <a href="<?= base_url('admin') ?>" class="brand me-3">Job Portal</a>
    <div class="li-search-wrap d-none d-md-block">
        <i class="bi bi-search"></i>
        <input type="text" class="search-box" placeholder="Search">
    </div>
    <div class="ms-auto d-flex align-items-center">
        <a href="<?= base_url('admin') ?>" class="li-nav-icon <?= (uri_string() === 'admin') ? 'active' : '' ?>"><i class="bi bi-house-door<?= (uri_string() === 'admin') ? '-fill' : '' ?>"></i><span class="nav-label">Home</span></a>
        <?php if (in_array($role ?? '', ['agency_owner', 'recruiter'])): ?>
            <a href="<?= base_url('admin/jobs') ?>" class="li-nav-icon <?= str_contains(uri_string(), 'admin/jobs') ? 'active' : '' ?>"><i class="bi bi-briefcase<?= str_contains(uri_string(), 'admin/jobs') ? '-fill' : '' ?>"></i><span class="nav-label">Jobs</span></a>
            <a href="<?= base_url('admin/candidates') ?>" class="li-nav-icon <?= str_contains(uri_string(), 'admin/candidates') ? 'active' : '' ?>"><i class="bi bi-people<?= str_contains(uri_string(), 'admin/candidates') ? '-fill' : '' ?>"></i><span class="nav-label">Candidates</span></a>
            <a href="<?= base_url('admin/ats') ?>" class="li-nav-icon <?= str_contains(uri_string(), 'admin/ats') ? 'active' : '' ?>"><i class="bi bi-kanban<?= str_contains(uri_string(), 'admin/ats') ? '-fill' : '' ?>"></i><span class="nav-label">ATS</span></a>
        <?php endif; ?>
        <?php if (($role ?? '') === 'candidate'): ?>
            <a href="<?= base_url('admin/jobs') ?>" class="li-nav-icon <?= str_contains(uri_string(), 'admin/jobs') ? 'active' : '' ?>"><i class="bi bi-briefcase<?= str_contains(uri_string(), 'admin/jobs') ? '-fill' : '' ?>"></i><span class="nav-label">Jobs</span></a>
            <a href="<?= base_url('admin/applications') ?>" class="li-nav-icon <?= str_contains(uri_string(), 'admin/applications') ? 'active' : '' ?>"><i class="bi bi-file-earmark-text<?= str_contains(uri_string(), 'admin/applications') ? '-fill' : '' ?>"></i><span class="nav-label">Applications</span></a>
        <?php endif; ?>
        <a href="<?= base_url('admin/messages') ?>" class="li-nav-icon"><i class="bi bi-chat-dots"></i><span class="nav-label">Messages</span></a>
        <a href="<?= base_url('admin/notifications') ?>" class="li-nav-icon">
            <i class="bi bi-bell"></i><span class="nav-label">Alerts</span>
        </a>
        <?php if (in_array($role ?? '', ['agency_owner', 'recruiter'])): ?>
            <span class="li-pill li-pill-blue ms-2" id="topbarCreditBalance" style="white-space:nowrap;"><i class="bi bi-coin"></i> <span id="creditCountValue">—</span><span class="credit-label"> credits</span></span>
        <?php endif; ?>
        <div class="dropdown ms-2">
            <a href="#" class="d-flex align-items-center" data-bs-toggle="dropdown">
                <span class="avatar-circle" style="<?= isset($photoUrl) && $photoUrl ? "background-image:url('" . esc($photoUrl) . "');background-size:cover;background-position:center;" : '' ?>">
                    <?= (isset($photoUrl) && $photoUrl) ? '' : esc(strtoupper(substr($userName ?? 'U', 0, 1))) ?>
                </span>
            </a>
            <ul class="dropdown-menu dropdown-menu-end">
                <li><span class="dropdown-item-text fw-bold"><?= esc($userName ?? '') ?></span></li>
                <li><span class="dropdown-item-text text-muted small"><?= esc(ucwords(str_replace('_', ' ', $role ?? ''))) ?></span></li>
                <li><hr class="dropdown-divider"></li>
                <?php if (($role ?? '') === 'agency_owner'): ?>
                    <li><a class="dropdown-item" href="<?= base_url('admin/billing') ?>">Billing</a></li>
                    <li><a class="dropdown-item" href="<?= base_url('admin/team') ?>">Team</a></li>
                <?php endif; ?>
                <li><a class="dropdown-item" href="<?= base_url('logout') ?>">Sign Out</a></li>
            </ul>
        </div>
    </div>
</nav>

<?php if (session()->getFlashdata('success')): ?>
    <div class="container-fluid px-4 mt-3"><div class="alert alert-success py-2"><?= esc(session()->getFlashdata('success')) ?></div></div>
<?php endif; ?>
<?php if (session()->getFlashdata('error')): ?>
    <div class="container-fluid px-4 mt-3"><div class="alert alert-danger py-2"><?= esc(session()->getFlashdata('error')) ?></div></div>
<?php endif; ?>

<div class="container-fluid" id="panelContainer" style="max-width: 1128px; margin-top: 20px;">
    <div class="d-md-none mb-2" id="mobileMenuToggleWrap">
        <button class="btn btn-li-outline btn-sm" type="button" data-bs-toggle="collapse" data-bs-target="#mobileSidebarCollapse">
            <i class="bi bi-list"></i> Menu
        </button>
    </div>
    <div class="d-flex gap-3 align-items-start flex-column flex-md-row" id="panelLayoutRow">
        <div class="collapse d-md-block" id="mobileSidebarCollapse">
            <?= $this->renderSection('sidebar') ?>
        </div>
        <div class="flex-grow-1" id="panelMainContent" style="min-width:0; width: 100%;">
            <?= $this->renderSection('content') ?>
        </div>
    </div>
</div>

<div class="toast-container position-fixed bottom-0 end-0 p-3" id="toastHost"></div>

<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<script>
const API_BASE = "<?= rtrim(base_url('api/v1'), '/') ?>";

function showToast(message, isError = false) {
    const host = document.getElementById('toastHost');
    const el = document.createElement('div');
    el.className = `toast align-items-center text-white ${isError ? 'bg-danger' : 'bg-success'} border-0`;
    el.setAttribute('role', 'alert');
    el.innerHTML = `<div class="d-flex"><div class="toast-body">${message}</div>
        <button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast"></button></div>`;
    host.appendChild(el);
    const toast = new bootstrap.Toast(el, { delay: 4000 });
    toast.show();
    el.addEventListener('hidden.bs.toast', () => el.remove());
}

async function apiFetch(path, options = {}) {
    const res = await fetch(`${API_BASE}${path}`, {
        ...options,
        credentials: 'include',
        headers: {
            'Content-Type': 'application/json',
            ...(options.headers || {}),
        },
    });
    let json;
    try { json = await res.json(); } catch (e) { json = { success: false, errors: [{ message: 'Unexpected server response.' }] }; }
    if (!res.ok || !json.success) {
        const msg = json.errors?.[0]?.message || 'Something went wrong.';
        throw new Error(msg);
    }
    return json;
}

function escapeHtml(str) {
    const div = document.createElement('div');
    div.textContent = str ?? '';
    return div.innerHTML;
}

function timeAgo(dateVal) {
    if (!dateVal) return '';
    // typeof null === 'object' in JS (a long-standing language quirk), so
    // this must check for null explicitly BEFORE the typeof check, or a
    // genuinely-null date crashes with "Cannot read properties of null".
    const dateStr = (typeof dateVal === 'object' && dateVal !== null) ? dateVal.date : dateVal;
    if (!dateStr) return '';
    const diff = (Date.now() - new Date(dateStr.replace(' ', 'T'))) / 1000;
    if (diff < 60) return 'just now';
    if (diff < 3600) return Math.floor(diff/60) + 'm ago';
    if (diff < 86400) return Math.floor(diff/3600) + 'h ago';
    return Math.floor(diff/86400) + 'd ago';
}

// Same object-vs-string-vs-null defensiveness as timeAgo() — see its comment.
function formatDateTime(dateVal) {
    if (!dateVal) return '';
    const dateStr = (typeof dateVal === 'object' && dateVal !== null) ? dateVal.date : dateVal;
    if (!dateStr) return '';
    return new Date(dateStr.replace(' ', 'T')).toLocaleString();
}

// Shared helper for inline "just the date part" formatting.
function dateOnly(dateVal) {
    if (!dateVal) return '';
    const dateStr = (typeof dateVal === 'object' && dateVal !== null) ? dateVal.date : dateVal;
    return (dateStr || '').substring(0, 10);
}

// Shown in the topbar for agency roles — kept here (not per-page) so the
// balance stays visible and up to date no matter which panel page is open.
(async () => {
    const el = document.getElementById('creditCountValue');
    if (!el) return; // not an agency role, topbar badge not rendered
    try {
        const res = await apiFetch('/billing/credits');
        el.textContent = res.data.balance;
    } catch (e) { el.textContent = '—'; }
})();
</script>
<?= $this->renderSection('scripts') ?>
</body>
</html>
