<?= $this->extend("layout/main_layout"); ?>

<?= $this->section("content"); ?>
<main class="flex-1 p-6 overflow-auto" x-data="reportModule()">
    <div class="flex justify-between items-center mb-6 no-print">
        <div>
            <h1 class="text-2xl font-bold text-base-content tracking-tight">Monthly QC Report</h1>
            <p class="text-sm mt-1 opacity-70">View summary and Levey-Jennings charts for laboratory tests</p>
        </div>
        <div class="flex gap-2">
            <button @click="window.print()" class="btn btn-outline btn-sm" :disabled="!selectedTest">
                <i class="fa-solid fa-print mr-2"></i>
                Print Report
            </button>
        </div>
    </div>

    <!-- Filters -->
    <div class="bg-base-100 rounded-xl border border-base-300 shadow-sm p-4 mb-6 no-print">
        <div class="flex flex-wrap gap-6 items-center">
            <div class="form-control">
                <label class="label pt-0">
                    <span class="label-text font-semibold opacity-60 uppercase text-[10px]">Reporting Month</span>
                </label>
                <div class="join">
                    <button @click="prevMonth()" class="join-item btn btn-sm btn-outline border-base-300"><i
                            class="fa-solid fa-chevron-left"></i></button>
                    <input type="month" x-model="month" @change="onMonthChange()"
                        class="join-item input input-bordered input-sm w-36 text-center font-medium bg-base-200/30">
                    <button @click="nextMonth()" class="join-item btn btn-sm btn-outline border-base-300"><i
                            class="fa-solid fa-chevron-right"></i></button>
                </div>
            </div>

            <div class="divider divider-horizontal mx-0 hidden sm:flex"></div>

            <div class="form-control flex-1 max-w-xs">
                <label class="label pt-0">
                    <span class="label-text font-semibold opacity-60 uppercase text-[10px]">Select Test</span>
                </label>
                <select x-model="selectedTest" @change="fetchData()"
                    class="select select-bordered select-sm w-full font-medium">
                    <option value="">Choose a test...</option>
                    <template x-for="test in tests" :key="test.testId">
                        <option :value="String(test.testId)" x-text="test.testName"></option>
                    </template>
                </select>
            </div>
        </div>
    </div>

    <!-- Loading State -->
    <div x-show="loading" class="flex flex-col items-center justify-center py-24 gap-4">
        <span class="loading loading-spinner loading-lg text-primary"></span>
        <p class="text-sm opacity-50 animate-pulse">Generating report...</p>
    </div>

    <!-- Empty State -->
    <div x-show="!loading && !selectedTest"
        class="bg-base-100 rounded-2xl border-2 border-dashed border-base-300 p-16 text-center">
        <div class="w-16 h-16 bg-base-200 rounded-full flex items-center justify-center mx-auto mb-4">
            <i class="fa-solid fa-chart-bar text-2xl opacity-20"></i>
        </div>
        <h3 class="font-bold text-lg">No Test Selected</h3>
        <p class="text-base-content/60 max-w-xs mx-auto">Please select a laboratory test to generate the monthly report.
        </p>
    </div>

    <!-- Report Content -->
    <div x-show="!loading && selectedTest && controls.length > 0" class="space-y-6 animate-in fade-in duration-500">

        <!-- Report Header (Print only) -->
        <div class="hidden print:block mb-8 border-b-2 border-base-content/20 pb-4">
            <div class="flex justify-between items-end">
                <div>
                    <h2 class="text-3xl font-black uppercase tracking-tighter" x-text="testName"></h2>
                    <p class="text-sm font-bold opacity-60" x-text="departmentName"></p>
                </div>
                <div class="text-right">
                    <p class="text-xl font-bold" x-text="monthDisplay"></p>
                    <p class="text-xs opacity-50">Report Generated: <?= date('d M Y H:i') ?></p>
                </div>
            </div>
        </div>

        <!-- summary stats -->
        <div class="flex flex-wrap gap-3 mb-6 no-print-gap">
            <template x-for="control in processedControls" :key="control.controlId">
                <div class="bg-base-100 rounded-xl border border-base-300 shadow-sm overflow-hidden flex flex-col w-full sm:w-[calc(50%-0.75rem)] lg:w-[calc(33.333%-0.75rem)] xl:w-[calc(25%-0.75rem)] print:w-[calc(33.333%-0.5rem)] print:text-[11px]">
                    <div class="bg-base-200/50 p-2 border-b border-base-300">
                        <div class="flex justify-between items-center gap-2">
                            <h3 class="font-bold truncate text-xs" x-text="control.controlName"></h3>
                            <span class="badge badge-xs badge-neutral shrink-0 print:scale-75" x-text="'Lot: ' + (control.lot || 'N/A')"></span>
                        </div>
                    </div>
                    <div class="p-2 flex-1 grid grid-cols-2 gap-2">
                        <div class="flex flex-col">
                            <span class="text-[9px] uppercase font-bold opacity-50">N</span>
                            <span class="text-sm font-mono font-bold" x-text="control.stats.n || 0"></span>
                        </div>
                        <div class="flex flex-col">
                            <span class="text-[9px] uppercase font-bold opacity-50">Mean</span>
                            <span class="text-sm font-mono font-bold text-primary"
                                x-text="formatNum(control.stats.mean)"></span>
                        </div>
                        <div class="flex flex-col">
                            <span class="text-[9px] uppercase font-bold opacity-50">SD</span>
                            <span class="text-sm font-mono font-bold" x-text="formatNum(control.stats.sd)"></span>
                        </div>
                        <div class="flex flex-col">
                            <span class="text-[9px] uppercase font-bold opacity-50">% CV</span>
                            <span class="text-sm font-mono font-bold"
                                :class="control.stats.cv > 5 ? 'text-warning' : 'text-success'"
                                x-text="formatNum(control.stats.cv, 1) + '%'"></span>
                        </div>
                    </div>
                    <div class="px-2 py-1 bg-base-200/30 text-[9px] flex justify-between border-t border-base-300 font-medium">
                        <span>Tgt: <span x-text="formatNum(control.mean)"></span>±<span x-text="formatNum(2*control.sd)"></span></span>
                        <span x-show="control.stats.mean" :class="getBiasClass(control)"
                            x-text="'B: ' + getBias(control) + '%'"></span>
                    </div>
                </div>
            </template>
        </div>

        <div class="flex flex-col xl:flex-row gap-6 items-start">
            <!-- Monthly Table -->
            <div class="w-full xl:w-80 print:w-72 shrink-0">
                <div
                    class="bg-base-100 rounded-xl border border-base-300 shadow-sm overflow-hidden print:break-inside-avoid">
                    <div class="p-4 border-b border-base-300 bg-base-200/50 print:p-2">
                        <h3 class="font-bold text-sm uppercase tracking-widest opacity-70 print:text-[10px]">Daily
                            Results Log</h3>
                    </div>
                    <div class="overflow-x-auto">
                        <table class="table table-xs w-full print:table-xs">
                            <thead class="bg-base-200/50">
                                <tr>
                                    <th class="w-10 text-center print:px-1">Day</th>
                                    <template x-for="control in controls" :key="control.controlId">
                                        <th class="text-center print:px-1 whitespace-normal break-words min-w-[60px] max-w-[100px] leading-tight" x-text="control.controlName"></th>
                                    </template>
                                </tr>
                            </thead>
                            <tbody>
                                <template x-for="day in daysInMonth" :key="day">
                                    <tr :class="isWeekend(day) ? 'bg-base-200/30' : ''">
                                        <td class="text-center font-mono font-bold print:px-1" x-text="day"></td>
                                        <template x-for="control in controls" :key="control.controlId">
                                            <td class="text-center print:px-1">
                                                <div class="flex flex-col gap-0.5">
                                                    <span class="font-mono text-[11px] print:text-[10px]"
                                                        :class="getValueClass(control, day)"
                                                        x-text="getResValue(control, day)"></span>
                                                    <span x-show="getResComment(control, day)"
                                                        class="text-[8px] opacity-40 italic block max-w-[80px] truncate mx-auto print:hidden"
                                                        :title="getResComment(control, day)"
                                                        x-text="getResComment(control, day)"></span>
                                                </div>
                                            </td>
                                        </template>
                                    </tr>
                                </template>
                            </tbody>
                        </table>
                    </div>
                </div>
            </div>

            <!-- Charts Section -->
            <div class="flex-1 space-y-6 w-full">
                <template x-for="control in processedControls" :key="'chart-'+control.controlId">
                    <div
                        class="bg-base-100 rounded-xl border border-base-300 shadow-sm p-4 print:break-inside-avoid print:p-2">
                        <div class="flex justify-between items-center mb-4 print:mb-1">
                            <h3 class="font-bold text-sm opacity-70 uppercase tracking-widest print:text-[10px]"
                                x-text="'Levey-Jennings: ' + control.controlName"></h3>
                            <div class="flex gap-2 text-[10px] print:text-[8px]">
                                <span class="flex items-center gap-1"><span
                                        class="w-2 h-2 rounded-full bg-success"></span>
                                    In Range</span>
                                <span class="flex items-center gap-1"><span
                                        class="w-2 h-2 rounded-full bg-error"></span>
                                    Out Range</span>
                            </div>
                        </div>
                        <div class="h-64 w-full print:h-48">
                            <canvas :id="'chart-' + control.controlId"></canvas>
                        </div>
                    </div>
                </template>
            </div>
        </div>

    </div>

    <!-- Error State -->
    <div x-show="!loading && selectedTest && controls.length === 0"
        class="bg-base-100 rounded-2xl border-2 border-dashed border-base-300 p-16 text-center">
        <div class="w-16 h-16 bg-base-200 rounded-full flex items-center justify-center mx-auto mb-4 text-warning">
            <i class="fa-solid fa-triangle-exclamation text-2xl"></i>
        </div>
        <h3 class="font-bold text-lg">No Data Found</h3>
        <p class="text-base-content/60 max-w-xs mx-auto">There are no records found for this test and month. Please
            check
            the selection or enter data in the Entry module.</p>
    </div>
</main>

<style>
    @media print {
        @page {
            size: A4;
            margin: 10mm;
        }

        body,
        .drawer,
        .drawer-content,
        main,
        .bg-base-100,
        .bg-base-200,
        .bg-base-300,
        .navbar,
        footer {
            background-color: white !important;
            background-image: none !important;
            color: black !important;
        }

        .no-print,
        .navbar,
        footer,
        .drawer-side,
        .divider {
            display: none !important;
        }

        main {
            padding: 0 !important;
            margin: 0 !important;
            width: 100% !important;
        }

        .shadow-sm,
        .shadow,
        .shadow-md,
        .shadow-lg,
        .shadow-xl,
        .shadow-2xl {
            box-shadow: none !important;
        }

        .border,
        .border-base-300,
        .rounded-xl,
        .rounded-2xl {
            border: 1px solid #ddd !important;
            border-radius: 4px !important;
        }

        /* Side by side layout for print */
        .flex-col.xl\:flex-row {
            flex-direction: row !important;
            gap: 10px !important;
            align-items: flex-start !important;
        }

        .flex-1 {
            flex: 1 1 0% !important;
        }

        .print\:w-72 {
            width: 18rem !important;
        }

        .shrink-0 {
            flex-shrink: 0 !important;
        }

        /* Condensed summary cards grid */
        .grid.print\:grid-cols-3 {
            display: grid !important;
            grid-template-columns: repeat(3, minmax(0, 1fr)) !important;
            gap: 8px !important;
            margin-bottom: 1rem !important;
        }

        /* Keep some semantic colors for data indicators but make them print-safe */
        .text-success {
            color: #065f46 !important;
        }

        .text-error {
            color: #991b1b !important;
        }

        .text-warning {
            color: #92400e !important;
        }

        .text-primary {
            color: #570df8 !important;
        }

        canvas {
            max-width: 100% !important;
            height: auto !important;
        }

        .table-xs th, .table-xs td {
            padding: 2px 4px !important;
            font-size: 9px !important;
        }
    }
</style>
<?= $this->endSection(); ?>

<?= $this->section("script"); ?>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
    document.addEventListener('alpine:init', () => {
        Alpine.data("reportModule", () => ({
            tests: [],
            selectedTest: '',
            controls: [],
            loading: false,
            month: '',
            charts: {},
            lastRequestId: 0,

            init() {
                const now = new Date();
                this.month = now.getFullYear() + '-' + String(now.getMonth() + 1).padStart(2, '0');
                this.fetchTests();
            },

            async fetchTests() {
                try {
                    const response = await fetch(`${BASEURL}api/master/tests`);
                    const json = await response.json();
                    this.tests = json.data || [];
                } catch (e) {
                    console.error('Failed to fetch tests:', e);
                }
            },

            onMonthChange() {
                if (this.selectedTest) {
                    this.fetchData();
                }
            },

            async fetchData() {
                if (!this.selectedTest) return;

                const requestId = ++this.lastRequestId;
                this.loading = true;
                try {
                    const params = new URLSearchParams({
                        test_id: this.selectedTest,
                        month: this.month
                    });
                    const response = await fetch(`${BASEURL}api/entry/monthly?${params}`);
                    const json = await response.json();

                    if (requestId !== this.lastRequestId) return;

                    if (json.status === 'success') {
                        this.controls = json.data.controls || [];
                        this.$nextTick(() => {
                            this.renderCharts();
                        });
                    }
                } catch (e) {
                    if (requestId === this.lastRequestId) {
                        console.error('Failed to fetch data:', e);
                    }
                } finally {
                    if (requestId === this.lastRequestId) {
                        this.loading = false;
                    }
                }
            },

            get processedControls() {
                return this.controls.map(c => {
                    const stats = this.calculateStats(c.results);
                    return { ...c, stats };
                });
            },

            calculateStats(results) {
                if (!results || typeof results !== 'object') return { n: 0, mean: null, sd: null, cv: null };

                const values = Object.values(results)
                    .filter(r => r !== null && r !== undefined)
                    .map(r => parseFloat(r.resValue))
                    .filter(v => !isNaN(v));

                if (values.length === 0) return { n: 0, mean: null, sd: null, cv: null };

                const n = values.length;
                const mean = values.reduce((a, b) => a + b, 0) / n;
                const variance = values.reduce((a, b) => a + Math.pow(b - mean, 2), 0) / (n > 1 ? n - 1 : 1);
                const sd = Math.sqrt(variance);
                const cv = mean !== 0 ? (sd / mean) * 100 : 0;

                return { n, mean, sd, cv };
            },

            renderCharts() {
                // Destroy existing charts
                Object.values(this.charts).forEach(chart => chart.destroy());
                this.charts = {};

                this.processedControls.forEach(control => {
                    const ctx = document.getElementById('chart-' + control.controlId);
                    if (!ctx) return;

                    const days = this.daysInMonth;
                    const data = days.map(day => {
                        const res = control.results[day];
                        return res && res.resValue !== null ? parseFloat(res.resValue) : null;
                    });

                    const targetMean = control.mean !== null ? parseFloat(control.mean) : null;
                    const targetSD = control.sd !== null ? parseFloat(control.sd) : null;

                    const datasets = [
                        {
                            label: control.controlName,
                            data: data,
                            borderColor: '#570df8',
                            backgroundColor: '#570df820',
                            borderWidth: 2,
                            pointRadius: 4,
                            pointBackgroundColor: data.map(v => {
                                if (v === null || targetMean === null || targetSD === null) return '#570df8';
                                const dev = Math.abs(v - targetMean);
                                return dev > 2 * targetSD ? '#ff52d9' : '#570df8';
                            }),
                            spanGaps: true,
                            tension: 0.1
                        }
                    ];

                    const chart = new Chart(ctx, {
                        type: 'line',
                        data: {
                            labels: days,
                            datasets: datasets
                        },
                        options: {
                            responsive: true,
                            maintainAspectRatio: false,
                            plugins: {
                                legend: { display: false },
                                tooltip: {
                                    callbacks: {
                                        label: function (context) {
                                            let label = 'Value: ' + context.parsed.y;
                                            if (targetMean !== null && targetSD !== null) {
                                                const dev = (context.parsed.y - targetMean) / targetSD;
                                                label += ` (${dev.toFixed(2)} SD)`;
                                            }
                                            return label;
                                        }
                                    }
                                }
                            },
                            animation: false,
                            scales: {
                                y: {
                                    beginAtZero: false,
                                    grid: {
                                        color: (context) => {
                                            if (targetMean === null || targetSD === null) return '#e5e7eb';
                                            const val = context.tick.value;
                                            if (Math.abs(val - targetMean) < 0.001) return '#10b98180'; // Mean line
                                            if (Math.abs(Math.abs(val - targetMean) - 2 * targetSD) < 0.001) return '#f59e0b40'; // 2SD
                                            if (Math.abs(Math.abs(val - targetMean) - 3 * targetSD) < 0.001) return '#ef444440'; // 3SD
                                            return '#e5e7eb';
                                        },
                                        lineWidth: (context) => {
                                            if (targetMean === null) return 1;
                                            const val = context.tick.value;
                                            if (Math.abs(val - targetMean) < 0.001) return 2;
                                            return 1;
                                        }
                                    },
                                    ticks: {
                                        font: { family: 'monospace', size: 10 }
                                    }
                                },
                                x: {
                                    grid: { display: false },
                                    ticks: { font: { family: 'monospace', size: 10 } }
                                }
                            }
                        }
                    });

                    if (targetMean !== null && targetSD !== null) {
                        const min = Math.min(...data.filter(v => v !== null), targetMean - 3.5 * targetSD);
                        const max = Math.max(...data.filter(v => v !== null), targetMean + 3.5 * targetSD);
                        chart.options.scales.y.min = min;
                        chart.options.scales.y.max = max;

                        // Force ticks at target mean and SD levels if possible, 
                        // or just let Chart.js decide but we highlighted the grid lines.
                    }

                    chart.update();
                    this.charts[control.controlId] = chart;
                });
            },

            get testName() {
                const test = this.tests.find(t => t.testId == this.selectedTest);
                return test ? test.testName : '';
            },

            get departmentName() {
                const test = this.tests.find(t => t.testId == this.selectedTest);
                // We don't have dept name in the test object from api/master/tests directly maybe?
                // Let's assume it might be there or just show "Department QC Report"
                return test && test.deptName ? test.deptName : 'Laboratory Department';
            },

            get monthDisplay() {
                if (!this.month) return '';
                const [year, month] = this.month.split('-');
                const date = new Date(year, month - 1);
                return date.toLocaleDateString('en-US', { month: 'long', year: 'numeric' });
            },

            get daysInMonth() {
                if (!this.month) return [];
                const [year, month] = this.month.split('-').map(Number);
                const days = new Date(year, month, 0).getDate();
                return Array.from({ length: days }, (_, i) => i + 1);
            },

            prevMonth() {
                const [year, month] = this.month.split('-').map(Number);
                const date = new Date(year, month - 2, 1);
                this.month = date.getFullYear() + '-' + String(date.getMonth() + 1).padStart(2, '0');
                this.onMonthChange();
            },

            nextMonth() {
                const [year, month] = this.month.split('-').map(Number);
                const date = new Date(year, month, 1);
                this.month = date.getFullYear() + '-' + String(date.getMonth() + 1).padStart(2, '0');
                this.onMonthChange();
            },

            isWeekend(day) {
                const [year, month] = this.month.split('-').map(Number);
                const date = new Date(year, month - 1, day);
                const dayOfWeek = date.getDay();
                return dayOfWeek === 0 || dayOfWeek === 6;
            },

            formatNum(val, dec = 2) {
                if (val === null || val === undefined) return '-';
                return parseFloat(val).toFixed(dec);
            },

            getBias(control) {
                if (!control.stats.mean || !control.mean) return '-';
                const bias = ((control.stats.mean - control.mean) / control.mean) * 100;
                return bias > 0 ? '+' + bias.toFixed(1) : bias.toFixed(1);
            },

            getBiasClass(control) {
                if (!control.stats.mean || !control.mean) return 'opacity-50';
                const bias = Math.abs(((control.stats.mean - control.mean) / control.mean) * 100);
                if (bias > 10) return 'text-error font-bold';
                if (bias > 5) return 'text-warning font-bold';
                return 'text-success font-bold';
            },

            getResValue(control, day) {
                const res = control.results[day];
                return res && res.resValue !== null ? res.resValue : '-';
            },

            getResComment(control, day) {
                const res = control.results[day];
                return res ? res.resComment : '';
            },

            getValueClass(control, day) {
                const res = control.results[day];
                if (!res || res.resValue === null) return 'opacity-20';

                if (control.mean === null || control.sd === null) return '';

                const val = parseFloat(res.resValue);
                const target = parseFloat(control.mean);
                const sd = parseFloat(control.sd);
                const dev = Math.abs(val - target);

                if (dev > 3 * sd) return 'text-error font-bold underline decoration-wavy';
                if (dev > 2 * sd) return 'text-error font-bold';
                return 'text-success';
            }
        }));
    });
</script>
<?= $this->endSection(); ?>