<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>School Years Management</title>
    <style>
        :root {
            --bg: #f4efe7;
            --bg-strong: #ece4d5;
            --panel: rgba(255, 252, 247, 0.94);
            --panel-alt: rgba(246, 238, 225, 0.96);
            --line: rgba(54, 41, 26, 0.12);
            --line-strong: rgba(32, 87, 68, 0.24);
            --ink: #1d2629;
            --muted: #677176;
            --accent: #1d6a55;
            --accent-deep: #114838;
            --warning: #a86511;
            --danger: #9d3131;
            --danger-soft: #f7dfdf;
            --success-soft: #dcefe6;
            --warning-soft: #f8eed8;
            --shadow: 0 26px 56px rgba(33, 26, 18, 0.12);
            --radius: 26px;
        }

        * {
            box-sizing: border-box;
        }

        body {
            margin: 0;
            min-height: 100vh;
            color: var(--ink);
            font-family: Georgia, "Times New Roman", serif;
            background:
                radial-gradient(circle at top left, rgba(29, 106, 85, 0.17), transparent 28%),
                radial-gradient(circle at top right, rgba(168, 101, 17, 0.13), transparent 24%),
                linear-gradient(180deg, #f8f2ea 0%, #efe7da 100%);
        }

        button,
        input,
        a {
            font: inherit;
        }

        a {
            color: inherit;
        }

        .page {
            max-width: 1600px;
            margin: 0 auto;
            padding: 24px 18px 42px;
            display: grid;
            grid-template-columns: minmax(250px, 290px) minmax(0, 1fr);
            gap: 20px;
        }

        .panel {
            background: var(--panel);
            border: 1px solid var(--line);
            border-radius: var(--radius);
            box-shadow: var(--shadow);
            backdrop-filter: blur(12px);
        }

        .sidebar {
            padding: 22px 18px;
            align-self: start;
            position: sticky;
            top: 18px;
        }

        .sidebar-label {
            margin: 0 0 16px;
            font-size: 0.8rem;
            letter-spacing: 0.18em;
            text-transform: uppercase;
            color: var(--accent);
        }

        .nav-title {
            margin: 0 0 16px;
            font-size: 1.6rem;
            line-height: 1;
        }

        .nav-list {
            display: grid;
            gap: 8px;
        }

        .nav-item {
            padding: 10px 12px;
            border-radius: 16px;
            color: var(--muted);
            text-decoration: none;
            border: 1px solid transparent;
        }

        .nav-item.active {
            color: var(--accent-deep);
            background: rgba(29, 106, 85, 0.11);
            border-color: rgba(29, 106, 85, 0.18);
            font-weight: 700;
        }

        .workspace {
            display: grid;
            gap: 18px;
        }

        .hero {
            padding: 26px 28px;
            display: grid;
            grid-template-columns: minmax(0, 1.4fr) minmax(270px, 0.8fr);
            gap: 18px;
        }

        .breadcrumbs {
            margin: 0 0 10px;
            font-size: 0.84rem;
            letter-spacing: 0.08em;
            text-transform: uppercase;
            color: var(--muted);
        }

        h1,
        h2,
        h3 {
            margin: 0;
            line-height: 1;
        }

        h1 {
            font-size: clamp(2rem, 4vw, 3.3rem);
            margin-bottom: 14px;
        }

        .hero-copy {
            margin: 0;
            max-width: 56rem;
            color: var(--muted);
            line-height: 1.55;
        }

        .hero-side {
            display: grid;
            gap: 12px;
            align-content: start;
        }

        .hero-card {
            padding: 16px 18px;
            border-radius: 18px;
            background: var(--panel-alt);
            border: 1px solid rgba(54, 41, 26, 0.08);
        }

        .hero-card strong {
            display: block;
            font-size: 1rem;
            margin-bottom: 6px;
        }

        .button-row,
        .card-actions,
        .form-actions {
            display: flex;
            flex-wrap: wrap;
            gap: 10px;
        }

        .button,
        button {
            appearance: none;
            border: 0;
            cursor: pointer;
            text-decoration: none;
            border-radius: 999px;
            padding: 11px 16px;
            display: inline-flex;
            align-items: center;
            justify-content: center;
            transition: transform 120ms ease, opacity 120ms ease;
        }

        .button:hover,
        button:hover {
            transform: translateY(-1px);
        }

        .button:disabled,
        button:disabled {
            opacity: 0.6;
            cursor: wait;
            transform: none;
        }

        .button-primary {
            background: var(--accent);
            color: #fff;
        }

        .button-secondary {
            background: #e9dcc5;
            color: var(--ink);
        }

        .button-ghost {
            background: transparent;
            border: 1px solid rgba(54, 41, 26, 0.18);
            color: var(--ink);
        }

        .button-danger {
            background: var(--danger);
            color: #fff;
        }

        .button-link {
            background: #fff;
            border: 1px solid rgba(54, 41, 26, 0.12);
        }

        .notice-stack {
            display: grid;
            gap: 10px;
        }

        .notice {
            border-radius: 18px;
            padding: 14px 16px;
            border: 1px solid rgba(54, 41, 26, 0.08);
        }

        .notice.success {
            background: var(--success-soft);
            color: var(--accent-deep);
        }

        .notice.warning {
            background: var(--warning-soft);
            color: #815112;
        }

        .notice.error {
            background: var(--danger-soft);
            color: var(--danger);
        }

        .stats-grid,
        .summary-grid {
            display: grid;
            grid-template-columns: repeat(4, minmax(0, 1fr));
            gap: 14px;
        }

        .stat-card,
        .summary-card {
            padding: 18px;
            border-radius: 20px;
            background: var(--panel-alt);
            border: 1px solid rgba(54, 41, 26, 0.08);
        }

        .stat-card strong,
        .summary-card strong {
            display: block;
            font-size: 1.8rem;
            margin-bottom: 6px;
        }

        .content-grid {
            display: grid;
            grid-template-columns: minmax(320px, 0.86fr) minmax(0, 1.14fr);
            gap: 18px;
        }

        .column {
            display: grid;
            gap: 18px;
            align-content: start;
        }

        .section {
            padding: 22px;
        }

        .section-header {
            display: flex;
            justify-content: space-between;
            gap: 14px;
            align-items: flex-start;
            margin-bottom: 16px;
        }

        .section-copy {
            margin-top: 8px;
            color: var(--muted);
            line-height: 1.48;
        }

        .status-pill {
            display: inline-flex;
            align-items: center;
            border-radius: 999px;
            padding: 7px 12px;
            font-size: 0.75rem;
            letter-spacing: 0.12em;
            text-transform: uppercase;
            background: #d8eee4;
            color: var(--accent-deep);
        }

        .status-pill.draft {
            background: #f1e5d0;
            color: #7d4c0f;
        }

        .status-pill.closed,
        .status-pill.blocked {
            background: #f4dddd;
            color: var(--danger);
        }

        .year-list,
        .preview-stack {
            display: grid;
            gap: 12px;
        }

        .year-card {
            padding: 18px;
            border: 1px solid var(--line);
            border-radius: 20px;
            background: rgba(255, 255, 255, 0.8);
        }

        .year-card.selected {
            border-color: var(--line-strong);
            box-shadow: inset 0 0 0 1px rgba(29, 106, 85, 0.1);
        }

        .year-meta {
            display: flex;
            justify-content: space-between;
            gap: 12px;
            align-items: flex-start;
        }

        .year-dates,
        .microcopy,
        .empty-state {
            color: var(--muted);
            line-height: 1.45;
        }

        .year-dates {
            margin-top: 10px;
            font-size: 0.94rem;
        }

        form {
            display: grid;
            gap: 14px;
        }

        .field-grid {
            display: grid;
            grid-template-columns: repeat(2, minmax(0, 1fr));
            gap: 12px;
        }

        label {
            display: grid;
            gap: 6px;
            color: var(--muted);
            font-size: 0.92rem;
        }

        input[type="text"],
        input[type="date"] {
            width: 100%;
            border-radius: 14px;
            border: 1px solid rgba(54, 41, 26, 0.18);
            padding: 12px 14px;
            background: rgba(255, 255, 255, 0.94);
            color: var(--ink);
        }

        input[type="checkbox"] {
            width: 18px;
            height: 18px;
            accent-color: var(--accent);
        }

        .checkbox {
            display: flex;
            gap: 10px;
            align-items: center;
            color: var(--ink);
        }

        .mono {
            font-family: "SFMono-Regular", ui-monospace, monospace;
        }

        .info-strip {
            padding: 14px 16px;
            border-radius: 18px;
            background: var(--panel-alt);
            border: 1px dashed rgba(54, 41, 26, 0.18);
            color: var(--muted);
        }

        .table-scroll {
            overflow-x: auto;
        }

        table {
            width: 100%;
            border-collapse: collapse;
            font-size: 0.93rem;
        }

        th,
        td {
            text-align: left;
            padding: 10px 8px;
            border-bottom: 1px solid rgba(54, 41, 26, 0.08);
            vertical-align: top;
        }

        th {
            color: var(--muted);
            font-size: 0.76rem;
            letter-spacing: 0.08em;
            text-transform: uppercase;
        }

        .split {
            display: grid;
            grid-template-columns: repeat(2, minmax(0, 1fr));
            gap: 16px;
        }

        .loading {
            color: var(--muted);
            font-style: italic;
        }

        @media (max-width: 1240px) {
            .page,
            .content-grid,
            .hero {
                grid-template-columns: 1fr;
            }

            .sidebar {
                position: static;
            }
        }

        @media (max-width: 760px) {
            .stats-grid,
            .summary-grid,
            .field-grid,
            .split {
                grid-template-columns: 1fr;
            }
        }
    </style>
</head>
<body>
    <div class="page">
        <aside class="panel sidebar">
            <p class="sidebar-label">Management</p>
            <h2 class="nav-title">Navigation</h2>
            <nav class="nav-list" aria-label="Administrator navigation">
                <a class="nav-item" href="#">Home</a>
                <a class="nav-item" href="#">CI views</a>
                <a class="nav-item" href="#">Attendance Management</a>
                <a class="nav-item" href="#">Classes</a>
                <a class="nav-item" href="#">Communication</a>
                <a class="nav-item" href="#">Competition</a>
                <a class="nav-item" href="#">Configuration</a>
                <a class="nav-item" href="#">Curriculum</a>
                <a class="nav-item" href="#">Event Management</a>
                <a class="nav-item" href="#">Exams</a>
                <a class="nav-item" href="#">Family</a>
                <a class="nav-item" href="#">Financial</a>
                <a class="nav-item" href="#">Inventory</a>
                <a class="nav-item" href="#">Notification Management</a>
                <a class="nav-item" href="#">Parents</a>
                <a class="nav-item" href="#">Printables</a>
                <a class="nav-item" href="#">Roles</a>
                <a class="nav-item active" href="/app/administrator/school-years">School Years Management</a>
                <a class="nav-item" href="#">Score Management</a>
                <a class="nav-item" href="#">Staffing</a>
                <a class="nav-item" href="#">Student-Affairs</a>
                <a class="nav-item" href="#">TimeOff Request</a>
                <a class="nav-item" href="#">Users</a>
            </nav>
        </aside>

        <main class="workspace">
            <section class="panel hero">
                <div>
                    <p class="breadcrumbs">Home / administrator / school-years</p>
                    <h1>School Years Management</h1>
                    <p class="hero-copy">
                        Replace the placeholder with a real control surface for creating draft years, editing metadata,
                        reopening a year, validating closure, previewing promotions and family balances, and closing the
                        active year through the same JWT-protected Laravel API used by the rest of the admin app.
                    </p>
                </div>
                <div class="hero-side">
                    <div class="hero-card">
                        <strong>SPA path</strong>
                        <span class="mono">/app/administrator/school-years</span>
                    </div>
                    <div class="hero-card">
                        <strong>API auth</strong>
                        <span>JWT Authorization: Bearer</span>
                    </div>
                    <div class="button-row">
                        <a class="button button-link" href="{{ $pageConfig['docs_url'] }}" target="_blank" rel="noreferrer">Open API docs</a>
                    </div>
                </div>
            </section>

            <div id="notice-stack" class="notice-stack"></div>
            <section id="stats-grid" class="stats-grid"></section>

            <div class="content-grid">
                <div class="column">
                    <section class="panel section">
                        <div class="section-header">
                            <div>
                                <h2>School Years</h2>
                                <div class="section-copy">
                                    Select a year to inspect it. Opening or reopening a year switches the live configuration
                                    and leaves the rest visible as historical records.
                                </div>
                            </div>
                        </div>
                        <div id="year-list" class="year-list"></div>
                    </section>

                    <section class="panel section">
                        <div class="section-header">
                            <div>
                                <h2>Create Draft Year</h2>
                                <div class="section-copy">Create the next year ahead of activation so closure can target a prepared record.</div>
                            </div>
                        </div>
                        <form id="create-form">
                            <div class="field-grid">
                                <label>
                                    Name
                                    <input type="text" name="name" required>
                                </label>
                                <label>
                                    Start date
                                    <input type="date" name="start_date" required>
                                </label>
                            </div>
                            <label>
                                End date
                                <input type="date" name="end_date" required>
                            </label>
                            <div class="form-actions">
                                <button type="submit" class="button-primary">Create draft year</button>
                            </div>
                        </form>
                    </section>
                </div>

                <div class="column">
                    <section class="panel section">
                        <div id="selected-summary"></div>
                    </section>

                    <section class="panel section">
                        <div id="selected-edit"></div>
                    </section>

                    <section class="panel section">
                        <div id="selected-inspection"></div>
                    </section>

                    <section class="panel section">
                        <div id="close-workflow"></div>
                    </section>
                </div>
            </div>
        </main>
    </div>

    <script>
        window.schoolYearPage = @json($pageConfig);
    </script>
    <script>
        (function () {
            const config = window.schoolYearPage || {};
            const state = {
                schoolYears: [],
                activeYear: null,
                selectedYearId: Number(config.selected_year_id || 0) || null,
                selectedSummary: null,
                selectedPromotionPreview: null,
                selectedParentBalances: null,
                closeDraft: null,
                closeValidation: null,
                closePreview: null,
                notices: [],
            };

            const elements = {
                noticeStack: document.getElementById('notice-stack'),
                statsGrid: document.getElementById('stats-grid'),
                yearList: document.getElementById('year-list'),
                createForm: document.getElementById('create-form'),
                selectedSummary: document.getElementById('selected-summary'),
                selectedEdit: document.getElementById('selected-edit'),
                selectedInspection: document.getElementById('selected-inspection'),
                closeWorkflow: document.getElementById('close-workflow'),
            };

            function escapeHtml(value) {
                return String(value ?? '')
                    .replace(/&/g, '&amp;')
                    .replace(/</g, '&lt;')
                    .replace(/>/g, '&gt;')
                    .replace(/"/g, '&quot;')
                    .replace(/'/g, '&#039;');
            }

            function formatMoney(value) {
                const number = Number(value || 0);
                return number.toLocaleString(undefined, {
                    minimumFractionDigits: 2,
                    maximumFractionDigits: 2,
                });
            }

            function formatDate(value) {
                if (!value) {
                    return '-';
                }

                const parsed = new Date(value + 'T00:00:00');
                if (Number.isNaN(parsed.getTime())) {
                    return value;
                }

                return parsed.toLocaleDateString(undefined, {
                    year: 'numeric',
                    month: 'short',
                    day: 'numeric',
                });
            }

            function statusLabel(value) {
                return String(value || '').toUpperCase();
            }

            function templateUrl(template, id) {
                return String(template || '').replace('__ID__', String(id));
            }

            function withQuery(url, params) {
                const target = new URL(url, window.location.origin);
                Object.entries(params || {}).forEach(([key, value]) => {
                    if (value !== null && value !== undefined && value !== '') {
                        target.searchParams.set(key, value);
                    }
                });
                return target.toString();
            }

            function defaultDraft() {
                const activeYear = state.activeYear;
                if (!activeYear) {
                    return Object.assign({
                        name: '',
                        start_date: '',
                        end_date: '',
                    }, config.default_draft || {});
                }

                const suggestedName = suggestNextName(activeYear.name) || (config.default_draft || {}).name || '';
                const suggestedStart = shiftYear(activeYear.start_date) || (config.default_draft || {}).start_date || '';
                const suggestedEnd = shiftYear(activeYear.end_date) || (config.default_draft || {}).end_date || '';

                return {
                    name: suggestedName,
                    start_date: suggestedStart,
                    end_date: suggestedEnd,
                };
            }

            function suggestNextName(name) {
                const fullRange = String(name || '').match(/^(\d{4})\s*-\s*(\d{4})$/);
                if (fullRange) {
                    return `${Number(fullRange[1]) + 1}-${Number(fullRange[2]) + 1}`;
                }

                const shortRange = String(name || '').match(/^(\d{4})\s*-\s*(\d{2})$/);
                if (shortRange) {
                    const nextStart = Number(shortRange[1]) + 1;
                    const nextEnd = (Number(shortRange[2]) + 1).toString().padStart(2, '0');
                    return `${nextStart}-${nextEnd}`;
                }

                return '';
            }

            function shiftYear(dateValue) {
                if (!dateValue) {
                    return '';
                }

                const parts = String(dateValue).split('-');
                if (parts.length !== 3) {
                    return '';
                }

                return `${Number(parts[0]) + 1}-${parts[1]}-${parts[2]}`;
            }

            function selectedYear() {
                return state.schoolYears.find((year) => Number(year.id) === Number(state.selectedYearId)) || null;
            }

            function pushNotice(type, message) {
                state.notices = [{ type, message }, ...state.notices].slice(0, 4);
                renderNotices();
            }

            function renderNotices() {
                if (!state.notices.length) {
                    elements.noticeStack.innerHTML = '';
                    return;
                }

                elements.noticeStack.innerHTML = state.notices.map((notice) => `
                    <div class="notice ${escapeHtml(notice.type)}">${escapeHtml(notice.message)}</div>
                `).join('');
            }

            function syncSelectedYearInUrl() {
                const url = new URL(window.location.href);
                if (state.selectedYearId) {
                    url.searchParams.set('year', String(state.selectedYearId));
                } else {
                    url.searchParams.delete('year');
                }
                window.history.replaceState({}, '', url.toString());
            }

            async function apiRequest(url, options) {
                const requestOptions = Object.assign({ method: 'GET' }, options || {});
                const headers = Object.assign({
                    'Accept': 'application/json',
                    'Authorization': `Bearer ${config.jwt}`,
                }, requestOptions.headers || {});

                if (requestOptions.body && !(requestOptions.body instanceof FormData)) {
                    headers['Content-Type'] = 'application/json';
                    requestOptions.body = JSON.stringify(requestOptions.body);
                }

                const response = await fetch(url, Object.assign({}, requestOptions, { headers }));
                const raw = await response.text();
                let json = {};

                try {
                    json = raw ? JSON.parse(raw) : {};
                } catch (error) {
                    json = { message: raw || 'Request failed.' };
                }

                if (!response.ok || json.ok === false || json.status === false) {
                    const messages = json.errors
                        ? Object.values(json.errors).flat().map(String)
                        : [json.message || `Request failed with status ${response.status}.`];
                    const failure = new Error(messages.join(' '));
                    failure.messages = messages;
                    failure.status = response.status;
                    throw failure;
                }

                return json;
            }

            function setFormBusy(form, isBusy) {
                if (!form) {
                    return;
                }

                form.querySelectorAll('button, input').forEach((field) => {
                    field.disabled = isBusy;
                });
            }

            function renderStats() {
                const activeName = state.activeYear ? state.activeYear.name : 'None';
                const closedCount = state.schoolYears.filter((year) => year.status === 'closed').length;
                const draftCount = state.schoolYears.filter((year) => year.status === 'draft').length;

                elements.statsGrid.innerHTML = `
                    <div class="stat-card panel">
                        <strong>${state.schoolYears.length}</strong>
                        Configured school years
                    </div>
                    <div class="stat-card panel">
                        <strong>${escapeHtml(activeName)}</strong>
                        Active year
                    </div>
                    <div class="stat-card panel">
                        <strong>${closedCount}</strong>
                        Closed years
                    </div>
                    <div class="stat-card panel">
                        <strong>${draftCount}</strong>
                        Draft years
                    </div>
                `;
            }

            function renderYearList() {
                if (!state.schoolYears.length) {
                    elements.yearList.innerHTML = '<div class="empty-state">No school years exist yet.</div>';
                    return;
                }

                elements.yearList.innerHTML = state.schoolYears.map((year) => {
                    const isSelected = Number(year.id) === Number(state.selectedYearId);
                    const isCurrent = Boolean(year.is_current);
                    const openLabel = year.status === 'draft' ? 'Open draft' : 'Reopen';

                    return `
                        <article class="year-card ${isSelected ? 'selected' : ''}">
                            <div class="year-meta">
                                <div>
                                    <h3>${escapeHtml(year.name)}</h3>
                                    <div class="year-dates">
                                        ${escapeHtml(formatDate(year.start_date))} to ${escapeHtml(formatDate(year.end_date))}
                                        ${year.closed_at ? `<br>Closed ${escapeHtml(year.closed_at)}` : ''}
                                    </div>
                                </div>
                                <span class="status-pill ${escapeHtml(year.status)}">${escapeHtml(statusLabel(year.status))}</span>
                            </div>
                            <div class="card-actions">
                                <button class="button-secondary" type="button" data-select-year="${year.id}">Inspect</button>
                                ${isCurrent ? '<span class="status-pill">Current</span>' : `<button class="button-primary" type="button" data-open-year="${year.id}">${escapeHtml(openLabel)}</button>`}
                            </div>
                        </article>
                    `;
                }).join('');
            }

            function renderCreateForm() {
                const defaults = defaultDraft();
                const form = elements.createForm;
                if (!form) {
                    return;
                }

                form.elements.name.value = defaults.name || '';
                form.elements.start_date.value = defaults.start_date || '';
                form.elements.end_date.value = defaults.end_date || '';
            }

            function renderSelectedSummary() {
                const year = selectedYear();
                if (!year) {
                    elements.selectedSummary.innerHTML = `
                        <div class="section-header">
                            <div>
                                <h2>Year Summary</h2>
                                <div class="section-copy">Select a school year from the list to view operational totals.</div>
                            </div>
                        </div>
                        <div class="empty-state">No school year is selected.</div>
                    `;
                    return;
                }

                const summary = state.selectedSummary;
                const totals = summary ? summary.totals : null;

                elements.selectedSummary.innerHTML = `
                    <div class="section-header">
                        <div>
                            <h2>${escapeHtml(year.name)}</h2>
                            <div class="section-copy">
                                Inspect the selected year before switching it live or closing it. Summary data is loaded from
                                <span class="mono">GET /api/v1/school-years/${escapeHtml(year.id)}/summary</span>.
                            </div>
                        </div>
                        <span class="status-pill ${escapeHtml(year.status)}">${escapeHtml(statusLabel(year.status))}</span>
                    </div>
                    <div class="info-strip">
                        ${escapeHtml(formatDate(year.start_date))} to ${escapeHtml(formatDate(year.end_date))}
                        ${year.is_current ? ' | Current configuration year' : ''}
                    </div>
                    ${totals ? `
                        <div class="summary-grid" style="margin-top:16px;">
                            <div class="summary-card">
                                <strong>${totals.students_considered}</strong>
                                Students considered
                            </div>
                            <div class="summary-card">
                                <strong>${totals.students_blocked}</strong>
                                Students blocked
                            </div>
                            <div class="summary-card">
                                <strong>${totals.parents_with_balances}</strong>
                                Parents with carryover
                            </div>
                            <div class="summary-card">
                                <strong>${formatMoney(totals.net_balance_to_transfer)}</strong>
                                Net balance impact
                            </div>
                        </div>
                    ` : '<div class="loading" style="margin-top:16px;">Loading summary…</div>'}
                `;
            }

            function renderSelectedEdit() {
                const year = selectedYear();
                if (!year) {
                    elements.selectedEdit.innerHTML = `
                        <div class="section-header">
                            <div>
                                <h2>Edit Year</h2>
                                <div class="section-copy">Metadata editing appears once a year is selected.</div>
                            </div>
                        </div>
                        <div class="empty-state">Select a school year to edit its dates or name.</div>
                    `;
                    return;
                }

                elements.selectedEdit.innerHTML = `
                    <div class="section-header">
                        <div>
                            <h2>Edit Selected Year</h2>
                            <div class="section-copy">
                                Updates use <span class="mono">PATCH /api/v1/school-years/${escapeHtml(year.id)}</span>.
                                Safe renames are allowed only while historical operational references do not depend on the old label.
                            </div>
                        </div>
                    </div>
                    <form id="edit-form" data-school-year-id="${year.id}">
                        <div class="field-grid">
                            <label>
                                Year name
                                <input type="text" name="name" value="${escapeHtml(year.name)}" required>
                            </label>
                            <label>
                                Start date
                                <input type="date" name="start_date" value="${escapeHtml(year.start_date)}" required>
                            </label>
                        </div>
                        <label>
                            End date
                            <input type="date" name="end_date" value="${escapeHtml(year.end_date)}" required>
                        </label>
                        <div class="form-actions">
                            <button type="submit" class="button-ghost">Save changes</button>
                        </div>
                    </form>
                `;
            }

            function renderInspection() {
                const year = selectedYear();
                if (!year) {
                    elements.selectedInspection.innerHTML = `
                        <div class="section-header">
                            <div>
                                <h2>Promotion And Balance Inspection</h2>
                                <div class="section-copy">Use the selected year to inspect promotions and parent balances.</div>
                            </div>
                        </div>
                        <div class="empty-state">Nothing to inspect until a school year is selected.</div>
                    `;
                    return;
                }

                const promotion = state.selectedPromotionPreview;
                const balances = state.selectedParentBalances;
                const promotionRows = (promotion?.rows || []).slice(0, 8).map((row) => `
                    <tr>
                        <td>${escapeHtml(row.student_name)}</td>
                        <td>${escapeHtml(row.current_grade || '-')}</td>
                        <td>${escapeHtml(row.promotion_action)}</td>
                        <td>${escapeHtml(row.target_grade || '-')}</td>
                        <td>${escapeHtml((row.warnings || []).join('; ') || '-')}</td>
                    </tr>
                `).join('');
                const balanceRows = (balances?.rows || []).slice(0, 8).map((row) => `
                    <tr>
                        <td>${escapeHtml(row.parent_name || `Parent #${row.parent_id}`)}</td>
                        <td>${escapeHtml((row.student_names || []).join(', ') || '-')}</td>
                        <td>${formatMoney(row.old_unpaid_balance)}</td>
                        <td>${formatMoney(row.credit_balance)}</td>
                        <td>${formatMoney(row.amount_to_transfer)}</td>
                    </tr>
                `).join('');

                elements.selectedInspection.innerHTML = `
                    <div class="section-header">
                        <div>
                            <h2>Promotion And Balance Inspection</h2>
                            <div class="section-copy">
                                Pull read-only previews from the selected year's standalone endpoints before deciding whether the year is ready to close.
                            </div>
                        </div>
                    </div>
                    <div class="button-row" style="margin-bottom:16px;">
                        <button type="button" class="button-secondary" data-load-preview="promotion">Load promotion preview</button>
                        <button type="button" class="button-secondary" data-load-preview="balances">Load parent balances</button>
                    </div>
                    <div class="split">
                        <div class="preview-stack">
                            <div class="info-strip">
                                <strong>Promotion preview</strong><br>
                                ${promotion ? `${promotion.summary.total_students} students scanned, ${promotion.summary.hold} hold rows.` : 'Not loaded yet.'}
                            </div>
                            ${promotion ? `
                                <div class="table-scroll">
                                    <table>
                                        <thead>
                                            <tr>
                                                <th>Student</th>
                                                <th>Current</th>
                                                <th>Action</th>
                                                <th>Target</th>
                                                <th>Warnings</th>
                                            </tr>
                                        </thead>
                                        <tbody>${promotionRows || '<tr><td colspan="5">No students found.</td></tr>'}</tbody>
                                    </table>
                                </div>
                            ` : '<div class="empty-state">Use the button above to fetch the promotion preview.</div>'}
                        </div>
                        <div class="preview-stack">
                            <div class="info-strip">
                                <strong>Parent balance preview</strong><br>
                                ${balances ? `${balances.summary.parents_with_non_zero_balance} parents with balances, net ${formatMoney(balances.summary.net_balance_to_transfer)}.` : 'Not loaded yet.'}
                            </div>
                            ${balances ? `
                                <div class="table-scroll">
                                    <table>
                                        <thead>
                                            <tr>
                                                <th>Parent</th>
                                                <th>Students</th>
                                                <th>Old due</th>
                                                <th>Credit</th>
                                                <th>Transfer</th>
                                            </tr>
                                        </thead>
                                        <tbody>${balanceRows || '<tr><td colspan="5">No balances found.</td></tr>'}</tbody>
                                    </table>
                                </div>
                            ` : '<div class="empty-state">Use the button above to fetch parent balances.</div>'}
                        </div>
                    </div>
                `;
            }

            function renderValidation(validation) {
                if (!validation) {
                    return '';
                }

                const errors = (validation.errors || []).map((message) => `<li>${escapeHtml(message)}</li>`).join('');
                const warnings = (validation.warnings || []).map((message) => `<li>${escapeHtml(message)}</li>`).join('');

                return `
                    <div class="preview-stack" style="margin-top:16px;">
                        <div class="section-header">
                            <div>
                                <h3>Closure Validation</h3>
                                <div class="section-copy">
                                    ${validation.can_close ? 'Validation passed. Review the preview and confirmation text before closing.' : 'Closure is blocked until the listed issues are resolved.'}
                                </div>
                            </div>
                            <span class="status-pill ${validation.can_close ? '' : 'blocked'}">${validation.can_close ? 'Ready' : 'Blocked'}</span>
                        </div>
                        <div class="summary-grid">
                            <div class="summary-card">
                                <strong>${validation.promotion_summary.total_students ?? 0}</strong>
                                Students scanned
                            </div>
                            <div class="summary-card">
                                <strong>${validation.promotion_summary.hold ?? 0}</strong>
                                Missing decisions
                            </div>
                            <div class="summary-card">
                                <strong>${validation.financial_summary.parents_with_non_zero_balance ?? 0}</strong>
                                Parents with balances
                            </div>
                            <div class="summary-card">
                                <strong>${formatMoney(validation.financial_summary.net_balance_to_transfer ?? 0)}</strong>
                                Net transfer
                            </div>
                        </div>
                        ${errors ? `<div class="notice error"><strong>Errors</strong><ul>${errors}</ul></div>` : ''}
                        ${warnings ? `<div class="notice warning"><strong>Warnings</strong><ul>${warnings}</ul></div>` : ''}
                    </div>
                `;
            }

            function renderClosePreview(preview) {
                if (!preview) {
                    return '';
                }

                const promotionRows = (preview.promotion_preview.rows || []).slice(0, 8).map((row) => `
                    <tr>
                        <td>${escapeHtml(row.student_name)}</td>
                        <td>${escapeHtml(row.current_grade || '-')}</td>
                        <td>${escapeHtml(row.promotion_action)}</td>
                        <td>${escapeHtml(row.target_grade || '-')}</td>
                        <td>${escapeHtml((row.warnings || []).join('; ') || '-')}</td>
                    </tr>
                `).join('');
                const balanceRows = (preview.parent_balances.rows || []).slice(0, 8).map((row) => `
                    <tr>
                        <td>${escapeHtml(row.parent_name || `Parent #${row.parent_id}`)}</td>
                        <td>${escapeHtml((row.student_names || []).join(', ') || '-')}</td>
                        <td>${formatMoney(row.old_unpaid_balance)}</td>
                        <td>${formatMoney(row.credit_balance)}</td>
                        <td>${formatMoney(row.amount_to_transfer)}</td>
                    </tr>
                `).join('');

                return `
                    <div class="split" style="margin-top:16px;">
                        <div class="preview-stack">
                            <div class="info-strip">
                                <strong>Promotion preview</strong><br>
                                ${preview.promotion_preview.summary.total_students} students scanned, ${preview.promotion_preview.summary.hold} hold rows.
                            </div>
                            <div class="table-scroll">
                                <table>
                                    <thead>
                                        <tr>
                                            <th>Student</th>
                                            <th>Current</th>
                                            <th>Action</th>
                                            <th>Target</th>
                                            <th>Warnings</th>
                                        </tr>
                                    </thead>
                                    <tbody>${promotionRows || '<tr><td colspan="5">No students found.</td></tr>'}</tbody>
                                </table>
                            </div>
                        </div>
                        <div class="preview-stack">
                            <div class="info-strip">
                                <strong>Parent balance preview</strong><br>
                                ${preview.parent_balances.summary.parents_with_non_zero_balance} parents with balances, net ${formatMoney(preview.parent_balances.summary.net_balance_to_transfer)}.
                            </div>
                            <div class="table-scroll">
                                <table>
                                    <thead>
                                        <tr>
                                            <th>Parent</th>
                                            <th>Students</th>
                                            <th>Old due</th>
                                            <th>Credit</th>
                                            <th>Transfer</th>
                                        </tr>
                                    </thead>
                                    <tbody>${balanceRows || '<tr><td colspan="5">No balances found.</td></tr>'}</tbody>
                                </table>
                            </div>
                        </div>
                    </div>
                `;
            }

            function renderCloseWorkflow() {
                if (!state.activeYear) {
                    elements.closeWorkflow.innerHTML = `
                        <div class="section-header">
                            <div>
                                <h2>Close Active Year</h2>
                                <div class="section-copy">An active school year is required before closure tooling becomes available.</div>
                            </div>
                        </div>
                        <div class="empty-state">There is no active school year right now.</div>
                    `;
                    return;
                }

                const defaults = state.closeDraft || Object.assign({
                    confirmation: '',
                    transfer_unpaid_balances: true,
                }, defaultDraft());
                elements.closeWorkflow.innerHTML = `
                    <div class="section-header">
                        <div>
                            <h2>Close ${escapeHtml(state.activeYear.name)}</h2>
                            <div class="section-copy">
                                Validate, preview, and close the active year using the same transaction-backed API endpoints exposed under
                                <span class="mono">/api/v1/school-years</span>.
                            </div>
                        </div>
                        <span class="status-pill">${escapeHtml(statusLabel(state.activeYear.status))}</span>
                    </div>
                    <form id="close-form" data-school-year-id="${state.activeYear.id}">
                        <div class="field-grid">
                            <label>
                                New year name
                                <input type="text" name="new_name" value="${escapeHtml(defaults.name)}" required>
                            </label>
                            <label>
                                New year start date
                                <input type="date" name="new_start_date" value="${escapeHtml(defaults.start_date)}" required>
                            </label>
                        </div>
                        <div class="field-grid">
                            <label>
                                New year end date
                                <input type="date" name="new_end_date" value="${escapeHtml(defaults.end_date)}" required>
                            </label>
                            <label>
                                Confirmation
                                <input class="mono" type="text" name="confirmation" value="${escapeHtml(defaults.confirmation || '')}" placeholder="CLOSE ${escapeHtml(state.activeYear.name)}" required>
                            </label>
                        </div>
                        <label class="checkbox">
                            <input type="checkbox" name="transfer_unpaid_balances" value="1" ${defaults.transfer_unpaid_balances === false ? '' : 'checked'}>
                            Transfer unpaid balances into the new year
                        </label>
                        <div class="form-actions">
                            <button type="button" class="button-secondary" data-close-action="validate">Validate</button>
                            <button type="button" class="button-ghost" data-close-action="preview">Preview</button>
                            <button type="submit" class="button-danger">Close year</button>
                        </div>
                    </form>
                    ${renderValidation(state.closeValidation)}
                    ${renderClosePreview(state.closePreview)}
                `;
            }

            function renderAll() {
                renderNotices();
                renderStats();
                renderYearList();
                renderCreateForm();
                renderSelectedSummary();
                renderSelectedEdit();
                renderInspection();
                renderCloseWorkflow();
            }

            async function loadSchoolYears(preferredId) {
                const response = await apiRequest(config.api.index);
                state.schoolYears = response.data || [];
                state.activeYear = state.schoolYears.find((year) => Boolean(year.is_current)) || null;

                if (!state.schoolYears.length) {
                    state.selectedYearId = null;
                    state.selectedSummary = null;
                    state.selectedPromotionPreview = null;
                    state.selectedParentBalances = null;
                    state.closeValidation = null;
                    state.closePreview = null;
                    renderAll();
                    return;
                }

                const requestedId = Number(preferredId || state.selectedYearId || 0);
                const hasRequested = state.schoolYears.some((year) => Number(year.id) === requestedId);
                state.selectedYearId = hasRequested
                    ? requestedId
                    : Number(state.activeYear?.id || state.schoolYears[0].id);

                state.selectedPromotionPreview = null;
                state.selectedParentBalances = null;
                state.closeDraft = null;
                syncSelectedYearInUrl();
                renderAll();
                await loadSelectedSummary();
            }

            async function loadSelectedSummary() {
                const year = selectedYear();
                if (!year) {
                    state.selectedSummary = null;
                    renderSelectedSummary();
                    renderSelectedEdit();
                    renderInspection();
                    return;
                }

                state.selectedSummary = null;
                renderSelectedSummary();
                const response = await apiRequest(templateUrl(config.api.summary, year.id));
                state.selectedSummary = response.data || null;
                renderSelectedSummary();
            }

            async function loadSelectedPreview(type) {
                const year = selectedYear();
                if (!year) {
                    return;
                }

                if (type === 'promotion') {
                    state.selectedPromotionPreview = null;
                } else {
                    state.selectedParentBalances = null;
                }
                renderInspection();

                const nextName = suggestNextName(year.name) || '';
                const url = type === 'promotion'
                    ? withQuery(templateUrl(config.api.promotion_preview, year.id), { to_school_year: nextName })
                    : withQuery(templateUrl(config.api.parent_balances, year.id), { to_school_year: nextName });
                const response = await apiRequest(url);

                if (type === 'promotion') {
                    state.selectedPromotionPreview = response.data || null;
                } else {
                    state.selectedParentBalances = response.data || null;
                }

                renderInspection();
            }

            function createPayloadFromForm(form) {
                const data = new FormData(form);
                return {
                    name: String(data.get('name') || '').trim(),
                    start_date: String(data.get('start_date') || '').trim(),
                    end_date: String(data.get('end_date') || '').trim(),
                };
            }

            function closePayloadFromForm(form, includeConfirmation) {
                const data = new FormData(form);
                const payload = {
                    new_school_year: {
                        name: String(data.get('new_name') || '').trim(),
                        start_date: String(data.get('new_start_date') || '').trim(),
                        end_date: String(data.get('new_end_date') || '').trim(),
                    },
                    transfer_unpaid_balances: data.get('transfer_unpaid_balances') === '1',
                };

                if (includeConfirmation) {
                    payload.confirmation = String(data.get('confirmation') || '').trim();
                }

                state.closeDraft = {
                    name: payload.new_school_year.name,
                    start_date: payload.new_school_year.start_date,
                    end_date: payload.new_school_year.end_date,
                    confirmation: String(data.get('confirmation') || '').trim(),
                    transfer_unpaid_balances: payload.transfer_unpaid_balances,
                };

                return payload;
            }

            async function handleCreate(form) {
                setFormBusy(form, true);

                try {
                    const response = await apiRequest(config.api.store, {
                        method: 'POST',
                        body: createPayloadFromForm(form),
                    });

                    pushNotice('success', `Draft school year ${response.data.name} created.`);
                    await loadSchoolYears(response.data.id);
                } finally {
                    setFormBusy(form, false);
                }
            }

            async function handleEdit(form) {
                const yearId = Number(form.getAttribute('data-school-year-id') || 0);
                setFormBusy(form, true);

                try {
                    const response = await apiRequest(templateUrl(config.api.update, yearId), {
                        method: 'PATCH',
                        body: createPayloadFromForm(form),
                    });

                    pushNotice('success', `School year ${response.data.name} updated.`);
                    await loadSchoolYears(response.data.id);
                } finally {
                    setFormBusy(form, false);
                }
            }

            async function handleOpenYear(yearId, button) {
                button.disabled = true;

                try {
                    const response = await apiRequest(templateUrl(config.api.reopen, yearId), {
                        method: 'POST',
                    });

                    pushNotice('success', `School year ${response.data.name} is now active.`);
                    state.closeDraft = null;
                    state.closeValidation = null;
                    state.closePreview = null;
                    await loadSchoolYears(response.data.id);
                } finally {
                    button.disabled = false;
                }
            }

            async function handleCloseAction(action, button) {
                const form = document.getElementById('close-form');
                if (!form) {
                    return;
                }

                const yearId = Number(form.getAttribute('data-school-year-id') || 0);
                button.disabled = true;

                try {
                    if (action === 'validate') {
                        const response = await apiRequest(templateUrl(config.api.validate_close, yearId), {
                            method: 'POST',
                            body: closePayloadFromForm(form, false),
                        });
                        state.closeValidation = response.validation || null;
                        state.closePreview = null;
                        renderCloseWorkflow();
                        return;
                    }

                    const response = await apiRequest(templateUrl(config.api.preview_close, yearId), {
                        method: 'POST',
                        body: closePayloadFromForm(form, false),
                    });
                    state.closeValidation = response.data?.validation || null;
                    state.closePreview = response.data || null;
                    renderCloseWorkflow();
                } finally {
                    button.disabled = false;
                }
            }

            async function handleCloseSubmit(form) {
                const yearId = Number(form.getAttribute('data-school-year-id') || 0);
                setFormBusy(form, true);

                try {
                    const response = await apiRequest(templateUrl(config.api.close, yearId), {
                        method: 'POST',
                        body: closePayloadFromForm(form, true),
                    });

                    const nextYear = response.data?.new_school_year;
                    pushNotice('success', `Closed ${response.data.closed_school_year.name} and opened ${nextYear.name}.`);
                    state.closeDraft = null;
                    state.closeValidation = null;
                    state.closePreview = null;
                    await loadSchoolYears(nextYear.id);
                } finally {
                    setFormBusy(form, false);
                }
            }

            document.addEventListener('click', async function (event) {
                const selectButton = event.target.closest('[data-select-year]');
                if (selectButton) {
                    state.selectedYearId = Number(selectButton.getAttribute('data-select-year'));
                    state.selectedPromotionPreview = null;
                    state.selectedParentBalances = null;
                    syncSelectedYearInUrl();
                    renderAll();

                    try {
                        await loadSelectedSummary();
                    } catch (error) {
                        pushNotice('error', error.message);
                    }
                    return;
                }

                const openButton = event.target.closest('[data-open-year]');
                if (openButton) {
                    try {
                        await handleOpenYear(Number(openButton.getAttribute('data-open-year')), openButton);
                    } catch (error) {
                        pushNotice('error', error.message);
                    }
                    return;
                }

                const previewButton = event.target.closest('[data-load-preview]');
                if (previewButton) {
                    previewButton.disabled = true;
                    try {
                        await loadSelectedPreview(previewButton.getAttribute('data-load-preview'));
                    } catch (error) {
                        pushNotice('error', error.message);
                    } finally {
                        previewButton.disabled = false;
                    }
                    return;
                }

                const closeActionButton = event.target.closest('[data-close-action]');
                if (closeActionButton) {
                    try {
                        await handleCloseAction(closeActionButton.getAttribute('data-close-action'), closeActionButton);
                    } catch (error) {
                        pushNotice('error', error.message);
                    }
                }
            });

            document.addEventListener('submit', async function (event) {
                const form = event.target;
                if (!(form instanceof HTMLFormElement)) {
                    return;
                }

                if (!['create-form', 'edit-form', 'close-form'].includes(form.id)) {
                    return;
                }

                event.preventDefault();

                try {
                    if (form.id === 'create-form') {
                        await handleCreate(form);
                        return;
                    }

                    if (form.id === 'edit-form') {
                        await handleEdit(form);
                        return;
                    }

                    await handleCloseSubmit(form);
                } catch (error) {
                    pushNotice('error', error.message);
                }
            });

            async function init() {
                elements.statsGrid.innerHTML = '<div class="loading">Loading school years…</div>';
                elements.yearList.innerHTML = '<div class="loading">Loading school years…</div>';
                elements.selectedSummary.innerHTML = '<div class="loading">Loading summary…</div>';
                elements.selectedEdit.innerHTML = '<div class="loading">Loading editor…</div>';
                elements.selectedInspection.innerHTML = '<div class="loading">Loading inspection tools…</div>';
                elements.closeWorkflow.innerHTML = '<div class="loading">Loading closure workflow…</div>';
                renderCreateForm();

                try {
                    await loadSchoolYears(state.selectedYearId);
                } catch (error) {
                    pushNotice('error', error.message);
                    renderAll();
                }
            }

            init();
        })();
    </script>
</body>
</html>
