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

<?= $this->section("content"); ?>
<main class="flex-1 p-6 overflow-auto" x-data="reportMergedModule()">
    <div class="flex justify-between items-center mb-6 no-print">
        <div>
            <h1 class="text-2xl font-bold text-base-content tracking-tight">Merged QC Report</h1>
            <p class="text-sm mt-1 opacity-70">All controls combined in a single vertical chart</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 merged 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 merged 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>

        <!-- Table and Chart Grid -->
        <div class="flex flex-col lg:flex-row gap-6">
            <!-- Monthly Table (Left) -->
            <div class="w-full lg:w-1/3">
                <div class="bg-base-100 rounded-xl border border-base-300 shadow-sm overflow-hidden h-full">
                    <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 max-h-[600px] overflow-y-auto">
                        <table class="table table-xs w-full print:table-xs">
                            <thead class="bg-base-200/50 sticky top-0">
                                <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>

            <!-- Merged Chart Section (Right) -->
            <div class="w-full lg:w-2/3">
                <div class="bg-base-100 rounded-xl border border-base-300 shadow-sm p-4 h-full">
                    <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]">
                            Merged Levey-Jennings Chart (All Controls)
                        </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-[560px] w-full relative">
                        <canvas id="mergedChart" class="w-full h-full"></canvas>
                    </div>
                </div>
            </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: portrait;
            margin: 3mm;
        }

        body {
            -webkit-print-color-adjust: exact;
            print-color-adjust: exact;
        }

        .no-print,
        .navbar,
        footer,
        .drawer-side,
        .divider,
        .mb-6:first-child,
        .flex.justify-between:first-child {
            display: none !important;
        }

        .space-y-6 > div:first-child {
            display: none !important;
        }

        .space-y-6 > div:nth-child(2) {
            margin-top: 0 !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;
        }

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

        .table-xs th, .table-xs td {
            padding: 1px !important;
            font-size: 6px !important;
            line-height: 1.2 !important;
        }

        .table {
            font-size: 6px !important;
            line-height: 1.2 !important;
        }

        .table tr {
            height: 15px !important;
        }

        .overflow-x-auto {
            overflow: visible !important;
        }

        .max-h-\[600px\] {
            max-height: 500px !important;
        }

        .flex-col.lg\:flex-row {
            flex-direction: row !important;
            display: flex !important;
            page-break-inside: avoid;
            break-inside: avoid;
        }

        .w-full.lg\:w-1\/3 {
            width: 35% !important;
            flex: 0 0 35% !important;
            max-width: 35% !important;
            page-break-inside: avoid;
            break-inside: avoid;
        }

        .w-full.lg\:w-2\/3 {
            width: 65% !important;
            flex: 0 0 65% !important;
            max-width: 65% !important;
            page-break-inside: avoid;
            break-inside: avoid;
        }

        .print\:block {
            display: flex !important;
        }

        .print\:mb-6 {
            margin-bottom: 0 !important;
        }

        .space-y-6 > * + * {
            margin-top: 1px !important;
        }

        .flex-wrap.gap-3 {
            gap: 4px !important;
        }

        .flex-wrap > div {
            min-height: auto !important;
        }

        .flex-wrap .grid-cols-2 {
            gap: 2px !important;
        }

        .text-[8px] {
            font-size: 6px !important;
        }

        .text-[9px] {
            font-size: 7px !important;
        }

        .table-xs span[class*="text-"] {
            font-size: 6px !important;
        }

        .animate-in,
        .fade-in {
            animation: none !important;
        }

        .h-\[560px\],
        .h-\[560px\] canvas,
        canvas#mergedChart {
            height: 500px !important;
        }

        .h-full {
            height: auto !important;
        }

        .print\:break-inside-avoid {
            break-inside: auto !important;
            page-break-inside: auto !important;
        }

        .print\:p-2 {
            padding: 2px !important;
        }

        .print\:text-\[10px\] {
            font-size: 8px !important;
        }

        .print\:text-\[11px\] {
            font-size: 8px !important;
        }

        .print\:scale-75 {
            transform: none !important;
        }

        .print:text-\[11px\] {
            font-size: 8px !important;
        }

        .badge-xs {
            font-size: 6px !important;
            padding: 1px 3px !important;
        }

        .text-\[9px\] {
            font-size: 7px !important;
        }

        .text-\[10px\] {
            font-size: 8px !important;
        }

        .text-\[11px\] {
            font-size: 8px !important;
        }

        .text-xs {
            font-size: 8px !important;
        }

        .text-sm {
            font-size: 9px !important;
        }

        .text-lg {
            font-size: 11px !important;
        }

        .text-2xl {
            font-size: 12px !important;
        }

        .text-3xl {
            font-size: 14px !important;
        }

        .font-bold.text-lg {
            font-size: 10px !important;
        }

        .font-bold.uppercase {
            font-size: 8px !important;
        }

        .p-4 {
            padding: 2px !important;
        }

        .mb-4,
        .mb-6 {
            margin-bottom: 2px !important;
        }

        .mb-4,
        .mb-6 {
            margin-bottom: 4px !important;
        }

        .gap-3 {
            gap: 4px !important;
        }

        .gap-6 {
            gap: 4px !important;
        }

        .flex-col.lg\:flex-row {
            gap: 4px !important;
        }

        .gap-2 {
            gap: 2px !important;
        }

        .space-y-6 > * + * {
            margin-top: 4px !important;
        }

        .p-2 {
            padding: 2px !important;
        }
    }
</style>
<?= $this->endSection(); ?>

<?= $this->section("script"); ?>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
    document.addEventListener('alpine:init', () => {
        Alpine.data("reportMergedModule", () => ({
            tests: [],
            selectedTest: '',
            controls: [],
            processedControls: [],
            loading: false,
            month: '',
            mergedChart: null,
            lastRequestId: 0,
            controlColors: [
                { border: '#570df8', bg: '#570df820' },
                { border: '#ff52d9', bg: '#ff52d920' },
                { border: '#10b981', bg: '#10b98120' },
                { border: '#f59e0b', bg: '#f59e0b20' },
                { border: '#ef4444', bg: '#ef444420' },
                { border: '#06b6d4', bg: '#06b6d420' },
            ],

            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.processedControls = this.controls.map(c => {
                            const stats = this.calculateStats(c.results);
                            return { ...c, stats };
                        });
                        this.$nextTick(() => {
                            this.renderMergedChart();
                        });
                    }
                } catch (e) {
                    if (requestId === this.lastRequestId) {
                        console.error('Failed to fetch data:', e);
                    }
                } finally {
                    if (requestId === this.lastRequestId) {
                        this.loading = false;
                    }
                }
            },



            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 };
            },

            renderMergedChart() {
                if (this.mergedChart) {
                    this.mergedChart.destroy();
                    this.mergedChart = null;
                }

                const canvas = document.getElementById('mergedChart');
                if (!canvas) return;

                const ctx = canvas.getContext('2d');
                if (!ctx) return;

                // Deep clone to break reactivity
                const controls = JSON.parse(JSON.stringify(this.controls));
                const days = JSON.parse(JSON.stringify(this.daysInMonth));
                
                if (!controls || controls.length === 0) return;

                const colors = ['#570df8', '#ff52d9', '#10b981', '#f59e0b', '#ef4444', '#06b6d4'];
                const bgColors = ['#570df820', '#ff52d920', '#10b98120', '#f59e0b20', '#ef444420', '#06b6d420'];

                const labels = days;
                const datasets = [];
                let allValues = [];

                controls.forEach((control, index) => {
                    const mean = parseFloat(control.mean) || 0;
                    const sd = parseFloat(control.sd) || 0;
                    const color = colors[index % colors.length];
                    const bgColor = bgColors[index % bgColors.length];
                    
                    const results = control.results || {};
                    const dataPoints = days.map(day => {
                        const res = results[day];
                        if (res && res.resValue !== null) {
                            const val = parseFloat(res.resValue);
                            allValues.push(val);
                            return val;
                        }
                        return null;
                    });

                    const pointColors = dataPoints.map(v => {
                        if (v === null || mean === 0 || sd === 0) return color;
                        return Math.abs(v - mean) > 2 * sd ? '#ef4444' : color;
                    });

                    datasets.push({
                        label: String(control.controlName || ''),
                        data: dataPoints,
                        borderColor: color,
                        backgroundColor: bgColor,
                        borderWidth: 2,
                        pointRadius: 4,
                        pointBackgroundColor: pointColors,
                        pointBorderColor: pointColors,
                        pointHoverRadius: 6,
                        spanGaps: true,
                        tension: 0.1
                    });
                });

                // Calculate scale
                const targets = controls.map(c => parseFloat(c.mean) || 0).filter(m => m !== 0);
                const sds = controls.map(c => parseFloat(c.sd) || 0).filter(s => s !== 0);
                
                let minScale = 0, maxScale = 100;
                if (allValues.length > 0 && targets.length > 0 && sds.length > 0) {
                    const minVal = Math.min(...allValues);
                    const maxVal = Math.max(...allValues);
                    const minTgt = Math.min(...targets) - 3.5 * Math.max(...sds);
                    const maxTgt = Math.max(...targets) + 3.5 * Math.max(...sds);
                    minScale = Math.min(minVal, minTgt);
                    maxScale = Math.max(maxVal, maxTgt);
                }

                const chartData = {
                    labels: labels,
                    datasets: datasets
                };

                const chartOptions = {
                    responsive: true,
                    maintainAspectRatio: false,
                    indexAxis: 'y',
                    interaction: {
                        mode: 'index',
                        intersect: false
                    },
                    plugins: {
                        legend: {
                            display: true,
                            position: 'bottom',
                            labels: {
                                usePointStyle: true,
                                pointStyle: 'line',
                                font: { size: 11 }
                            }
                        },
                        tooltip: {
                            callbacks: {
                                label: function(context) {
                                    return context.dataset.label + ': ' + context.parsed.x;
                                }
                            }
                        }
                    },
                    scales: {
                        x: {
                            min: minScale,
                            max: maxScale,
                            title: {
                                display: true,
                                text: 'Value',
                                font: { size: 11, weight: 'bold' }
                            },
                            grid: {
                                display: true,
                                color: '#e5e7eb'
                            },
                            ticks: {
                                font: { family: 'monospace', size: 10 }
                            }
                        },
                        y: {
                            reverse: true,
                            title: {
                                display: true,
                                text: 'Day',
                                font: { size: 11, weight: 'bold' }
                            },
                            grid: {
                                display: true,
                                color: '#e5e7eb'
                            },
                            ticks: {
                                stepSize: 1
                            }
                        }
                    }
                };

                this.mergedChart = new Chart(ctx, {
                    type: 'line',
                    data: chartData,
                    options: chartOptions
                });
            },

            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);
                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();
                const arr = new Array(days);
                for (let i = 0; i < days; i++) {
                    arr[i] = i + 1;
                }
                return arr;
            },

            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(); ?>