:root {
    --bg-soft: #f4faf6;
    --bg-deep: #d9efe0;
    --panel: #ffffff;
    --ink: #17352a;
    --ink-muted: #4f665d;
    --line: #d7e4de;
    --brand: #057a55;
    --brand-deep: #04553b;
    --brand-accent: #1fa47a;
    --danger-soft: #ffe7e7;
    --danger: #9a1f1f;
    --radius-lg: 18px;
    --radius-md: 12px;
    --shadow-soft: 0 14px 34px rgba(4, 85, 59, 0.13);
}

* {
    box-sizing: border-box;
}

body {
    margin: 0;
    min-height: 100vh;
    font-family: "Source Sans 3", "Segoe UI", sans-serif;
    color: var(--ink);
    background: linear-gradient(165deg, var(--bg-soft) 0%, #eef8f2 48%, var(--bg-deep) 100%);
    position: relative;
}

h1,
h2,
h3,
h4 {
    font-family: "Merriweather", Georgia, serif;
    margin-top: 0;
}

a {
    color: var(--brand-deep);
}

.page-aurora {
    position: fixed;
    top: -140px;
    right: -140px;
    width: 420px;
    height: 420px;
    border-radius: 50%;
    background: radial-gradient(circle, rgba(31, 164, 122, 0.38) 0%, rgba(31, 164, 122, 0) 70%);
    z-index: 0;
    pointer-events: none;
}

.page-grid {
    position: fixed;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    background-image: linear-gradient(rgba(6, 74, 53, 0.03) 1px, transparent 1px),
        linear-gradient(90deg, rgba(6, 74, 53, 0.03) 1px, transparent 1px);
    background-size: 30px 30px;
}

.app-shell {
    max-width: 1180px;
    margin: 0 auto;
    padding: 30px 20px 80px;
    position: relative;
    z-index: 1;
}

.site-header {
    display: grid;
    gap: 12px;
    grid-template-columns: 1.1fr 1fr auto auto;
    align-items: center;
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    background: rgba(255, 255, 255, 0.92);
    backdrop-filter: blur(6px);
    box-shadow: var(--shadow-soft);
    padding: 16px 18px;
}

.brand-block {
    min-width: 0;
}

.eyebrow {
    margin: 0;
    color: var(--ink-muted);
    text-transform: uppercase;
    letter-spacing: 0.09em;
    font-size: 0.73rem;
    font-weight: 700;
}

.brand-title {
    font-size: 1.23rem;
    font-weight: 700;
    text-decoration: none;
    color: var(--brand-deep);
}

.main-nav {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
}

.nav-link {
    text-decoration: none;
    color: var(--ink);
    border: 1px solid transparent;
    border-radius: 999px;
    padding: 8px 13px;
    font-weight: 600;
    transition: all 0.2s ease;
}

.nav-link:hover,
.nav-link.is-active {
    border-color: var(--brand-accent);
    background: #e7f6ef;
    color: var(--brand-deep);
}

.user-pill {
    border-left: 1px solid var(--line);
    padding-left: 14px;
    display: grid;
}

.user-pill span {
    font-weight: 700;
}

.user-pill small {
    color: var(--ink-muted);
    text-transform: uppercase;
    letter-spacing: 0.07em;
    font-size: 0.66rem;
}

.logout-form {
    margin: 0;
}

.app-main {
    margin-top: 24px;
}

.page-card {
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-soft);
    padding: 24px;
    margin-bottom: 18px;
    animation: rise-in 0.45s ease both;
}

.page-card + .page-card {
    animation-delay: 0.07s;
}

.role-chip {
    display: inline-flex;
    align-items: center;
    border-radius: 999px;
    border: 1px solid var(--brand-accent);
    background: #e6f6ef;
    color: var(--brand-deep);
    padding: 5px 12px;
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-weight: 700;
}

.stat-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
    gap: 12px;
}

.stat-tile {
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
    padding: 14px;
    background: linear-gradient(150deg, #ffffff 0%, #f5fbf8 100%);
}

.stat-tile p {
    margin: 0;
    color: var(--ink-muted);
    font-size: 0.88rem;
}

.stat-value {
    display: block;
    font-size: 1.65rem;
    font-weight: 700;
    margin-top: 6px;
}

.quick-links {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
}

.quick-links form {
    margin: 0;
}

.primary-button,
.secondary-button,
.ghost-button {
    border-radius: 10px;
    padding: 9px 14px;
    cursor: pointer;
    font-weight: 700;
    border: 1px solid transparent;
    transition: all 0.2s ease;
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.primary-button {
    background: linear-gradient(130deg, var(--brand) 0%, var(--brand-accent) 100%);
    color: #ffffff;
}

.primary-button:hover {
    transform: translateY(-1px);
    box-shadow: 0 8px 20px rgba(5, 122, 85, 0.28);
}

.secondary-button {
    color: var(--brand-deep);
    border-color: var(--brand-accent);
    background: #ecf8f3;
}

.secondary-button:hover {
    background: #dff4eb;
}

.ghost-button {
    background: transparent;
    border-color: var(--line);
    color: var(--ink);
}

.ghost-button:hover {
    border-color: var(--brand-accent);
    color: var(--brand-deep);
}

.project-list {
    width: 100%;
    border-collapse: collapse;
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
    overflow: hidden;
}

.project-list th,
.project-list td {
    border-bottom: 1px solid var(--line);
    padding: 12px;
    text-align: left;
    vertical-align: top;
}

.project-list th {
    background: #f0f9f4;
    font-size: 0.85rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--ink-muted);
}

.status-pill {
    display: inline-flex;
    font-size: 0.73rem;
    border-radius: 999px;
    border: 1px solid var(--line);
    padding: 3px 10px;
    text-transform: capitalize;
    background: #f9fcfa;
}

.inline-actions {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
}

.flash-list {
    list-style: none;
    padding: 0;
    margin: 0 0 16px;
}

.flash-item {
    border-radius: 10px;
    padding: 10px 12px;
    border: 1px solid var(--line);
    background: #eef8f3;
    margin-bottom: 8px;
}

.flash-error {
    border-color: #f7c8c8;
    background: var(--danger-soft);
    color: var(--danger);
}

.auth-wrap {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 330px;
    gap: 16px;
    align-items: stretch;
}

.auth-panel,
.auth-sidecard {
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-soft);
    background: rgba(255, 255, 255, 0.94);
}

.auth-panel {
    padding: 28px;
}

.auth-panel h1 {
    margin-bottom: 8px;
}

.auth-note {
    color: var(--ink-muted);
    margin-top: 0;
    margin-bottom: 18px;
}

.auth-sidecard {
    padding: 24px;
    background: linear-gradient(190deg, #f0faf5 0%, #dff3e9 100%);
}

.auth-form {
    display: grid;
    gap: 12px;
}

.field-group {
    display: grid;
    gap: 6px;
}

.field-group label {
    font-weight: 700;
}

.field-group input {
    border: 1px solid var(--line);
    border-radius: 10px;
    padding: 10px 11px;
    font: inherit;
    background: #ffffff;
}

.field-group select,
.field-group input[type="file"] {
    border: 1px solid var(--line);
    border-radius: 10px;
    padding: 10px 11px;
    font: inherit;
    background: #ffffff;
}

.field-group ul.errorlist {
    margin: 0;
    padding-left: 18px;
    color: var(--danger);
}

.form-errors {
    background: var(--danger-soft);
    color: var(--danger);
    border: 1px solid #f7c8c8;
    border-radius: 10px;
    padding: 9px 11px;
}

.auth-help {
    color: var(--ink-muted);
    margin-bottom: 0;
}

.site-footer {
    max-width: 1180px;
    margin: 0 auto;
    padding: 0 20px 28px;
    color: var(--ink-muted);
    position: relative;
    z-index: 1;
}

.empty-state {
    color: var(--ink-muted);
    margin: 0;
}

@keyframes rise-in {
    from {
        opacity: 0;
        transform: translateY(8px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

@media (max-width: 980px) {
    .site-header {
        grid-template-columns: 1fr;
    }

    .user-pill {
        border-left: 0;
        padding-left: 0;
        border-top: 1px solid var(--line);
        padding-top: 10px;
    }

    .auth-wrap {
        grid-template-columns: 1fr;
    }
}

@media (max-width: 640px) {
    .app-shell {
        padding: 20px 12px 64px;
    }

    .page-card {
        padding: 18px;
    }

    .project-list {
        display: block;
        overflow-x: auto;
        white-space: nowrap;
    }
}

/* Chart Styles */
.chart-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
    gap: 24px;
    margin-top: 20px;
}

.chart-card {
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
    padding: 20px;
    box-shadow: var(--shadow-soft);
}

.chart-card h3 {
    margin: 0 0 8px 0;
    color: var(--ink);
    font-size: 1.1rem;
}

.chart-subtitle {
    margin: 0 0 16px 0;
    color: var(--ink-muted);
    font-size: 0.9rem;
}

.chart-container {
    position: relative;
    height: 300px;
    width: 100%;
}

@media (max-width: 768px) {
    .chart-grid {
        grid-template-columns: 1fr;
    }
    
    .chart-container {
        height: 250px;
    }
}

.dashboard-intro {
    display: grid;
    gap: 18px;
    grid-template-columns: minmax(0, 1.45fr) minmax(280px, 0.85fr);
    align-items: start;
}

.dashboard-meta-panel {
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    padding: 18px;
    background: linear-gradient(155deg, #ffffff 0%, #eef9f3 100%);
}

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

.dashboard-meta-grid strong {
    display: block;
    font-size: 1.35rem;
    margin-top: 4px;
}

.dashboard-meta-grid span {
    color: var(--ink-muted);
    font-size: 0.82rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

.dashboard-note,
.dashboard-empty-copy {
    color: var(--ink-muted);
}

.dashboard-controls {
    display: grid;
    gap: 18px;
}

.dashboard-control-grid {
    display: grid;
    gap: 12px;
    grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
}

.dashboard-control {
    display: grid;
    gap: 7px;
}

.dashboard-control label {
    font-size: 0.84rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--ink-muted);
}

.dashboard-control select,
.dashboard-control input {
    width: 100%;
    border: 1px solid var(--line);
    border-radius: 10px;
    padding: 11px 12px;
    font: inherit;
    color: var(--ink);
    background: #ffffff;
}

.dashboard-control select:focus,
.dashboard-control input:focus {
    outline: 2px solid rgba(31, 164, 122, 0.25);
    border-color: var(--brand-accent);
}

.dashboard-chart-types {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
}

.chart-type-button {
    border: 1px solid var(--line);
    background: #ffffff;
    color: var(--ink);
    border-radius: 999px;
    padding: 9px 14px;
    font: inherit;
    font-weight: 700;
    cursor: pointer;
    transition: all 0.2s ease;
}

.chart-type-button:hover,
.chart-type-button.is-active {
    border-color: var(--brand-accent);
    background: #e8f7ef;
    color: var(--brand-deep);
}

.dashboard-status-row {
    display: flex;
    gap: 12px;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: center;
}

.dashboard-status,
.dashboard-suggestion {
    border-radius: 999px;
    padding: 8px 12px;
    border: 1px solid var(--line);
    background: #f8fcf9;
    font-size: 0.86rem;
}

.dashboard-status.is-loading {
    border-color: var(--brand-accent);
    color: var(--brand-deep);
    background: #ecf8f3;
}

.dashboard-status.is-error {
    border-color: #f2bcbc;
    color: var(--danger);
    background: var(--danger-soft);
}

.dashboard-stage {
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    padding: 18px;
    background: linear-gradient(180deg, rgba(255, 255, 255, 0.96) 0%, rgba(235, 248, 241, 0.9) 100%);
}

.dashboard-canvas-shell {
    position: relative;
    min-height: 360px;
}

.dashboard-canvas-shell canvas {
    width: 100% !important;
    height: 360px !important;
}

.dashboard-empty-panel {
    display: grid;
    place-items: center;
    min-height: 360px;
    text-align: center;
    padding: 24px;
    border-radius: var(--radius-md);
    border: 1px dashed var(--line);
    background: rgba(255, 255, 255, 0.7);
}

.dashboard-summary-row {
    display: flex;
    gap: 12px;
    flex-wrap: wrap;
    color: var(--ink-muted);
    font-size: 0.92rem;
    margin-top: 12px;
}

.dashboard-stats-grid {
    display: grid;
    gap: 12px;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
}

.dashboard-stat-card {
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
    padding: 16px;
    background: linear-gradient(150deg, #ffffff 0%, #f5fbf8 100%);
}

.dashboard-stat-card span {
    display: block;
    color: var(--ink-muted);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-size: 0.74rem;
}

.dashboard-stat-card strong {
    display: block;
    font-size: 1.45rem;
    margin-top: 8px;
}

.dashboard-table-wrap {
    overflow-x: auto;
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
}

.dashboard-table tbody td {
    white-space: nowrap;
}

.dashboard-table-empty {
    text-align: center;
    color: var(--ink-muted);
}

@media (max-width: 920px) {
    .dashboard-intro {
        grid-template-columns: 1fr;
    }

    .dashboard-meta-grid {
        grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
    }
}

@media (max-width: 640px) {
    .dashboard-status-row {
        align-items: stretch;
    }

    .dashboard-status,
    .dashboard-suggestion {
        width: 100%;
    }

    .chart-type-button {
        flex: 1 1 calc(50% - 10px);
    }

    .dashboard-canvas-shell,
    .dashboard-canvas-shell canvas,
    .dashboard-empty-panel {
        min-height: 300px;
        height: 300px !important;
    }
}
*** Add File: c:\Users\safwan\Documents\kpijazan\templates\projects\project_dashboard.html
{% extends "base.html" %}

{% block title %}{{ project.name }} Dashboard | KPI Jazan{% endblock %}

{% block content %}
<section class="page-card">
    <div class="dashboard-intro">
        <div>
            <p class="eyebrow">Interactive KPI Dashboard</p>
            <h1>{{ project.name }}</h1>
            <p>{{ project.description|default:"Explore validated KPI records with interactive chart controls, live aggregation, and a data table." }}</p>
            <div class="quick-links">
                <a class="ghost-button" href="{% url 'projects:project-detail' slug=project.slug %}">Back to Project Overview</a>
                {% if can_submit_data %}
                    <a class="primary-button" href="{% url 'projects:project-data-entry' slug=project.slug %}">Open Data Entry Workspace</a>
                {% endif %}
            </div>
        </div>
        <aside class="dashboard-meta-panel">
            <div class="dashboard-meta-grid">
                <div>
                    <span>KPIs Available</span>
                    <strong>{{ dashboard_kpi_count }}</strong>
                </div>
                <div>
                    <span>Validated Records</span>
                    <strong>{{ validated_record_count }}</strong>
                </div>
                <div>
                    <span>Chart Types</span>
                    <strong>{{ dashboard_config.chartTypes|length }}</strong>
                </div>
                <div>
                    <span>Aggregations</span>
                    <strong>{{ dashboard_config.aggregations|length }}</strong>
                </div>
            </div>
            <p class="dashboard-note">Switch KPI, axes, aggregation, and filters without reloading the page. The chart updates from a single project-scoped JSON endpoint.</p>
        </aside>
    </div>
</section>

{% if dashboard_config.kpis %}
    <section class="page-card">
        <div class="dashboard-controls">
            <div>
                <h2>Chart Controls</h2>
                <p class="dashboard-note">Pick a KPI, choose the fields to compare, and filter the date range or entity in scope.</p>
            </div>

            <div class="dashboard-control-grid">
                <div class="dashboard-control">
                    <label for="dashboard-kpi-select">KPI</label>
                    <select id="dashboard-kpi-select"></select>
                </div>
                <div class="dashboard-control">
                    <label for="dashboard-x-field-select">X Axis</label>
                    <select id="dashboard-x-field-select"></select>
                </div>
                <div class="dashboard-control">
                    <label for="dashboard-y-field-select">Y Axis</label>
                    <select id="dashboard-y-field-select"></select>
                </div>
                <div class="dashboard-control">
                    <label for="dashboard-aggregation-select">Aggregation</label>
                    <select id="dashboard-aggregation-select"></select>
                </div>
                <div class="dashboard-control">
                    <label for="dashboard-entity-select">Entity Filter</label>
                    <select id="dashboard-entity-select"></select>
                </div>
                <div class="dashboard-control">
                    <label for="dashboard-start-period">Start Period</label>
                    <input id="dashboard-start-period" type="date">
                </div>
                <div class="dashboard-control">
                    <label for="dashboard-end-period">End Period</label>
                    <input id="dashboard-end-period" type="date">
                </div>
            </div>

            <div>
                <h3>Chart Type</h3>
                <div class="dashboard-chart-types" id="dashboard-chart-types">
                    {% for chart_type in dashboard_config.chartTypes %}
                        <button class="chart-type-button" type="button" data-chart-type="{{ chart_type.key }}">{{ chart_type.label }}</button>
                    {% endfor %}
                </div>
            </div>

            <div class="dashboard-status-row">
                <div class="dashboard-status" id="dashboard-status">Waiting for chart data.</div>
                <div class="dashboard-suggestion" id="dashboard-suggestion">Auto-suggest will activate after the first data load.</div>
            </div>
        </div>
    </section>

    <section class="page-card">
        <h2 id="dashboard-chart-title">Live KPI Chart</h2>
        <div class="dashboard-stage">
            <div class="dashboard-canvas-shell" id="dashboard-canvas-shell">
                <canvas id="dashboard-chart-canvas"></canvas>
            </div>
            <div class="dashboard-empty-panel" id="dashboard-empty-panel" hidden>
                <div>
                    <h3>No data available</h3>
                    <p class="dashboard-empty-copy">Adjust the KPI or filters to find validated records for this view.</p>
                </div>
            </div>
        </div>
        <div class="dashboard-summary-row">
            <span id="dashboard-point-summary">0 chart points</span>
            <span id="dashboard-record-summary">0 underlying records</span>
        </div>
    </section>

    <section class="page-card">
        <h2>Summary Stats</h2>
        <div class="dashboard-stats-grid">
            <article class="dashboard-stat-card">
                <span>Minimum</span>
                <strong id="dashboard-stat-min">-</strong>
            </article>
            <article class="dashboard-stat-card">
                <span>Maximum</span>
                <strong id="dashboard-stat-max">-</strong>
            </article>
            <article class="dashboard-stat-card">
                <span>Average</span>
                <strong id="dashboard-stat-avg">-</strong>
            </article>
            <article class="dashboard-stat-card">
                <span>Total</span>
                <strong id="dashboard-stat-total">-</strong>
            </article>
        </div>
    </section>

    <section class="page-card">
        <h2>Data Table</h2>
        <p class="dashboard-note">These rows are the aggregated values powering the current chart.</p>
        <div class="dashboard-table-wrap">
            <table class="project-list dashboard-table">
                <thead>
                    <tr>
                        <th id="dashboard-table-x-heading">X Axis</th>
                        <th id="dashboard-table-y-heading">Y Axis</th>
                        <th>Underlying Records</th>
                    </tr>
                </thead>
                <tbody id="dashboard-table-body">
                    <tr>
                        <td colspan="3" class="dashboard-table-empty">Load a chart to inspect the aggregated table.</td>
                    </tr>
                </tbody>
            </table>
        </div>
    </section>

    {{ dashboard_config|json_script:"project-dashboard-config" }}
    <script>
    document.addEventListener('DOMContentLoaded', function () {
        const configElement = document.getElementById('project-dashboard-config');
        if (!configElement) {
            return;
        }

        const dashboardConfig = JSON.parse(configElement.textContent);
        const kpis = dashboardConfig.kpis || [];
        const kpiById = new Map(kpis.map((kpi) => [String(kpi.id), kpi]));
        if (!kpis.length) {
            return;
        }

        const formatter = new Intl.NumberFormat(undefined, { maximumFractionDigits: 2 });
        const kpiSelect = document.getElementById('dashboard-kpi-select');
        const xFieldSelect = document.getElementById('dashboard-x-field-select');
        const yFieldSelect = document.getElementById('dashboard-y-field-select');
        const aggregationSelect = document.getElementById('dashboard-aggregation-select');
        const entitySelect = document.getElementById('dashboard-entity-select');
        const startPeriodInput = document.getElementById('dashboard-start-period');
        const endPeriodInput = document.getElementById('dashboard-end-period');
        const chartButtons = Array.from(document.querySelectorAll('[data-chart-type]'));
        const statusElement = document.getElementById('dashboard-status');
        const suggestionElement = document.getElementById('dashboard-suggestion');
        const chartTitleElement = document.getElementById('dashboard-chart-title');
        const pointSummaryElement = document.getElementById('dashboard-point-summary');
        const recordSummaryElement = document.getElementById('dashboard-record-summary');
        const tableBody = document.getElementById('dashboard-table-body');
        const xHeading = document.getElementById('dashboard-table-x-heading');
        const yHeading = document.getElementById('dashboard-table-y-heading');
        const statMin = document.getElementById('dashboard-stat-min');
        const statMax = document.getElementById('dashboard-stat-max');
        const statAvg = document.getElementById('dashboard-stat-avg');
        const statTotal = document.getElementById('dashboard-stat-total');
        const chartCanvas = document.getElementById('dashboard-chart-canvas');
        const chartShell = document.getElementById('dashboard-canvas-shell');
        const emptyPanel = document.getElementById('dashboard-empty-panel');

        let chartInstance = null;
        let currentPayload = null;
        let debounceHandle = null;
        let currentAbortController = null;
        let currentChartType = 'line';
        let manualChartSelection = false;

        function formatMetric(value, unit) {
            if (value === null || value === undefined || value === '') {
                return '-';
            }
            const suffix = unit ? ` ${unit}` : '';
            return `${formatter.format(value)}${suffix}`;
        }

        function formatXAxis(value, fieldMeta) {
            if (value === null || value === undefined || value === '') {
                return 'Unspecified';
            }

            if (fieldMeta && fieldMeta.is_date) {
                const dateValue = new Date(value);
                if (!Number.isNaN(dateValue.getTime())) {
                    return dateValue.toLocaleDateString();
                }
            }

            if (typeof value === 'boolean') {
                return value ? 'Yes' : 'No';
            }

            if (typeof value === 'number') {
                return formatter.format(value);
            }

            return String(value);
        }

        function setStatus(message, state) {
            statusElement.textContent = message;
            statusElement.classList.remove('is-loading', 'is-error');
            if (state) {
                statusElement.classList.add(state);
            }
        }

        function populateSelect(selectElement, options, selectedValue, emptyLabel) {
            selectElement.innerHTML = '';
            if (emptyLabel) {
                const emptyOption = document.createElement('option');
                emptyOption.value = '';
                emptyOption.textContent = emptyLabel;
                selectElement.appendChild(emptyOption);
            }

            options.forEach((option) => {
                const optionElement = document.createElement('option');
                optionElement.value = option.value;
                optionElement.textContent = option.label;
                selectElement.appendChild(optionElement);
            });

            if (selectedValue && Array.from(selectElement.options).some((option) => option.value === selectedValue)) {
                selectElement.value = selectedValue;
            }
        }

        function currentKpi() {
            return kpiById.get(kpiSelect.value) || kpis[0];
        }

        function syncKpiControls() {
            const selectedKpi = currentKpi();
            populateSelect(
                xFieldSelect,
                selectedKpi.x_fields.map((field) => ({ value: field.key, label: field.label })),
                xFieldSelect.value || selectedKpi.default_x_field
            );
            populateSelect(
                yFieldSelect,
                selectedKpi.y_fields.map((field) => ({ value: field.key, label: field.label })),
                yFieldSelect.value || selectedKpi.default_y_field
            );
            populateSelect(
                entitySelect,
                (selectedKpi.entity_options || []).map((entity) => ({ value: entity, label: entity })),
                entitySelect.value,
                'All entities'
            );
            chartTitleElement.textContent = `${selectedKpi.name} Live Chart`;
        }

        function suggestedChartType(payload) {
            if (!payload || !payload.series || !payload.series.length) {
                return 'bar';
            }

            if (payload.x_field.is_numeric && payload.y_field.is_numeric) {
                return 'scatter';
            }

            if (payload.x_field.is_date) {
                return 'line';
            }

            if (payload.series.length <= 5) {
                return 'doughnut';
            }

            return 'bar';
        }

        function chartTypeIsCompatible(chartType, payload) {
            if (chartType !== 'scatter') {
                return true;
            }
            return Boolean(payload && payload.x_field && payload.x_field.is_numeric && payload.y_field && payload.y_field.is_numeric);
        }

        function updateChartButtons() {
            chartButtons.forEach((button) => {
                button.classList.toggle('is-active', button.dataset.chartType === currentChartType);
            });
        }

        function buildPalette(size) {
            const palette = ['#057a55', '#1fa47a', '#93d2b4', '#0f5132', '#84b59f', '#e0f3ea', '#3d8361', '#274c43'];
            return Array.from({ length: size }, (_, index) => palette[index % palette.length]);
        }

        function renderChart() {
            if (chartInstance) {
                chartInstance.destroy();
                chartInstance = null;
            }

            if (!currentPayload || !currentPayload.series || !currentPayload.series.length) {
                chartShell.hidden = true;
                emptyPanel.hidden = false;
                updateChartButtons();
                return;
            }

            const suggestedType = suggestedChartType(currentPayload);
            if (!manualChartSelection || !chartTypeIsCompatible(currentChartType, currentPayload)) {
                currentChartType = suggestedType;
                manualChartSelection = false;
            }

            suggestionElement.textContent = `Auto-suggested: ${suggestedType.charAt(0).toUpperCase()}${suggestedType.slice(1)}`;
            updateChartButtons();
            chartShell.hidden = false;
            emptyPanel.hidden = true;

            const labels = currentPayload.series.map((item) => formatXAxis(item.x, currentPayload.x_field));
            const values = currentPayload.series.map((item) => item.y);
            const unitSuffix = currentPayload.unit ? ` (${currentPayload.unit})` : '';
            const datasetLabel = `${currentPayload.y_agg_label} of ${currentPayload.y_field.label}${unitSuffix}`;
            const chartOptions = {
                responsive: true,
                maintainAspectRatio: false,
                plugins: {
                    legend: {
                        display: true,
                        position: 'top'
                    },
                    tooltip: {
                        callbacks: {
                            label: function (context) {
                                const rawValue = context.raw && typeof context.raw === 'object' && context.raw !== null && 'y' in context.raw
                                    ? context.raw.y
                                    : context.raw;
                                return `${datasetLabel}: ${formatMetric(rawValue, currentPayload.unit)}`;
                            }
                        }
                    }
                }
            };

            let chartConfig;
            if (currentChartType === 'scatter') {
                const scatterData = currentPayload.series
                    .map((item) => ({ x: Number(item.x), y: Number(item.y) }))
                    .filter((item) => Number.isFinite(item.x) && Number.isFinite(item.y));

                chartConfig = {
                    type: 'scatter',
                    data: {
                        datasets: [{
                            label: datasetLabel,
                            data: scatterData,
                            pointRadius: 5,
                            pointHoverRadius: 7,
                            borderColor: '#057a55',
                            backgroundColor: 'rgba(5, 122, 85, 0.35)'
                        }]
                    },
                    options: {
                        ...chartOptions,
                        scales: {
                            x: {
                                type: 'linear',
                                title: {
                                    display: true,
                                    text: currentPayload.x_field.label
                                }
                            },
                            y: {
                                beginAtZero: true,
                                title: {
                                    display: true,
                                    text: `${currentPayload.y_agg_label} of ${currentPayload.y_field.label}${unitSuffix}`
                                }
                            }
                        }
                    }
                };
            } else {
                const palette = buildPalette(values.length);
                chartConfig = {
                    type: currentChartType,
                    data: {
                        labels: labels,
                        datasets: [{
                            label: datasetLabel,
                            data: values,
                            borderColor: currentChartType === 'radar' ? '#057a55' : '#04553b',
                            backgroundColor: ['pie', 'doughnut'].includes(currentChartType)
                                ? palette.map((color) => `${color}cc`)
                                : currentChartType === 'line'
                                    ? 'rgba(5, 122, 85, 0.14)'
                                    : 'rgba(31, 164, 122, 0.78)',
                            borderWidth: 2,
                            fill: currentChartType === 'line',
                            tension: currentChartType === 'line' ? 0.32 : 0.1
                        }]
                    },
                    options: {
                        ...chartOptions,
                        scales: ['pie', 'doughnut', 'radar'].includes(currentChartType)
                            ? {}
                            : {
                                x: {
                                    title: {
                                        display: true,
                                        text: currentPayload.x_field.label
                                    }
                                },
                                y: {
                                    beginAtZero: true,
                                    title: {
                                        display: true,
                                        text: `${currentPayload.y_agg_label} of ${currentPayload.y_field.label}${unitSuffix}`
                                    }
                                }
                            }
                    }
                };
            }

            chartInstance = new Chart(chartCanvas, chartConfig);
        }

        function renderStats() {
            const unit = currentPayload ? currentPayload.unit : '';
            const stats = currentPayload ? currentPayload.stats : null;
            statMin.textContent = formatMetric(stats ? stats.min : null, unit);
            statMax.textContent = formatMetric(stats ? stats.max : null, unit);
            statAvg.textContent = formatMetric(stats ? stats.avg : null, unit);
            statTotal.textContent = formatMetric(stats ? stats.total : null, unit);
            pointSummaryElement.textContent = `${stats ? stats.point_count : 0} chart points`;
            recordSummaryElement.textContent = `${stats ? stats.record_total : 0} underlying records`;
        }

        function renderTable() {
            if (!currentPayload) {
                return;
            }

            xHeading.textContent = currentPayload.x_field.label;
            yHeading.textContent = `${currentPayload.y_agg_label} of ${currentPayload.y_field.label}`;

            if (!currentPayload.table.length) {
                tableBody.innerHTML = '<tr><td colspan="3" class="dashboard-table-empty">No aggregated rows are available for the current filters.</td></tr>';
                return;
            }

            tableBody.innerHTML = currentPayload.table.map((row) => `
                <tr>
                    <td>${formatXAxis(row.x, currentPayload.x_field)}</td>
                    <td>${formatMetric(row.y, currentPayload.unit)}</td>
                    <td>${formatter.format(row.record_count)}</td>
                </tr>
            `).join('');
        }

        function applyPayload(payload) {
            currentPayload = payload;
            chartTitleElement.textContent = `${payload.kpi} Live Chart`;
            renderStats();
            renderTable();
            renderChart();

            if (payload.has_series) {
                setStatus(`Loaded ${payload.y_agg_label.toLowerCase()} aggregation for ${payload.kpi}.`);
            } else {
                setStatus('No validated rows match the current KPI and filters.');
            }
        }

        function fetchChartData() {
            const selectedKpi = currentKpi();
            const query = new URLSearchParams({
                kpi_id: selectedKpi.id,
                x_field: xFieldSelect.value,
                y_field: yFieldSelect.value,
                y_agg: aggregationSelect.value
            });

            if (entitySelect.value) {
                query.set('entity_id', entitySelect.value);
            }
            if (startPeriodInput.value) {
                query.set('start_period', startPeriodInput.value);
            }
            if (endPeriodInput.value) {
                query.set('end_period', endPeriodInput.value);
            }

            if (currentAbortController) {
                currentAbortController.abort();
            }

            currentAbortController = new AbortController();
            setStatus('Loading chart data…', 'is-loading');

            fetch(`${dashboardConfig.apiUrl}?${query.toString()}`, {
                headers: { 'X-Requested-With': 'XMLHttpRequest' },
                signal: currentAbortController.signal
            })
                .then((response) => response.json().then((payload) => ({ ok: response.ok, payload })))
                .then(({ ok, payload }) => {
                    if (!ok) {
                        throw new Error(payload.error || 'Unable to load chart data.');
                    }
                    applyPayload(payload);
                })
                .catch((error) => {
                    if (error.name === 'AbortError') {
                        return;
                    }
                    setStatus(error.message, 'is-error');
                    currentPayload = {
                        table: [],
                        has_series: false,
                        stats: { point_count: 0, record_total: 0, min: null, max: null, avg: null, total: null },
                        x_field: { label: 'X Axis', is_date: false },
                        y_field: { label: 'Y Axis' },
                        y_agg_label: 'Selected',
                        unit: selectedKpi.unit,
                    };
                    renderStats();
                    renderTable();
                    renderChart();
                });
        }

        function scheduleFetch() {
            window.clearTimeout(debounceHandle);
            debounceHandle = window.setTimeout(fetchChartData, 220);
        }

        populateSelect(
            kpiSelect,
            kpis.map((kpi) => ({ value: String(kpi.id), label: kpi.name })),
            String(dashboardConfig.initialKpiId || kpis[0].id)
        );
        populateSelect(
            aggregationSelect,
            (dashboardConfig.aggregations || []).map((item) => ({ value: item.key, label: item.label })),
            'avg'
        );
        syncKpiControls();

        kpiSelect.addEventListener('change', function () {
            manualChartSelection = false;
            syncKpiControls();
            scheduleFetch();
        });

        [xFieldSelect, yFieldSelect, aggregationSelect, entitySelect, startPeriodInput, endPeriodInput].forEach((element) => {
            element.addEventListener('change', scheduleFetch);
        });

        chartButtons.forEach((button) => {
            button.addEventListener('click', function () {
                manualChartSelection = true;
                currentChartType = button.dataset.chartType;
                if (currentPayload) {
                    renderChart();
                }
            });
        });

        scheduleFetch();
    });
    </script>
{% else %}
    <section class="page-card">
        <h2>No KPIs available</h2>
        <p class="empty-state">Add KPI measurements to this project before opening the interactive dashboard.</p>
    </section>
{% endif %}
{% endblock %}
