// Carrier reliability layer — compares airline performance on the same route
// States: origin → destination → comparison
class CarrierLayer extends BaseLayer {
    constructor(viz) {
        super(viz);
        this.data = null;
        this.state = 'origin';
        this.origin = null;
        this.dest = null;
        this.routeKey = null;
    }

    async activate() {
        super.activate();
        if (!this.data) {
            try {
                const resp = await fetch('/data/carrier_reliability.json');
                this.data = await resp.json();
            } catch (err) {
                console.error('Failed to load carrier data:', err);
            }
        }
        this.state = 'origin';
        this.origin = null;
        this.dest = null;
        this.routeKey = null;
        this._renderPanel();
    }

    deactivate() {
        this.state = 'origin';
        this.origin = null;
        this.dest = null;
        this.routeKey = null;
        InfoPanel.clear();
        super.deactivate();
    }

    getLegendHTML() {
        return `
            <div class="layer-legend-title">Carrier Gap (same route)</div>
            <div class="layer-legend-row">
                <span class="legend-dot" style="background:#22c55e"></span> Low (&lt;5pp)
            </div>
            <div class="layer-legend-row">
                <span class="legend-dot" style="background:#eab308"></span> Moderate (5-15pp)
            </div>
            <div class="layer-legend-row">
                <span class="legend-dot" style="background:#ef4444"></span> High (&gt;15pp)
            </div>
            <div style="font-size:0.75rem;color:var(--text-muted);margin-top:0.5rem">
                pp = percentage points
            </div>
        `;
    }

    // --- layer hooks ---

    onAirportClick(d) {
        if (this.state === 'origin') {
            this._setOrigin(d.id);
            return true;
        }
        if (this.state === 'destination') {
            if (d.id === this.origin) { this._goBackToOrigin(); return true; }
            const key = this.origin + '-' + d.id;
            if (this.data[key]) { this._setDest(d.id); }
            return true;
        }
        if (this.state === 'comparison') {
            if (d.id === this.origin || d.id === this.dest) {
                this._goBackToDestination();
                return true;
            }
            const key = this.origin + '-' + d.id;
            if (this.data[key]) { this._setDest(d.id); }
            return true;
        }
        return false;
    }

    onBackgroundClick() {
        if (this.state === 'origin') return false;
        this._goBackToOrigin();
        return true;
    }

    getNodeColor(d) {
        if (this.state === 'origin') return null;
        if (this.state === 'destination') {
            if (d.id === this.origin) return null;
            if (this._isReachable(d.id)) return null;
            return '#d1d5db';
        }
        // comparison state
        if (d.id === this.origin || d.id === this.dest) return null;
        return '#d1d5db';
    }

    getEdgeColor(edge) {
        if (!this.data) return null;
        if (this.state === 'origin') return 'rgba(0,0,0,0)';

        const routeKey = `${edge.source}-${edge.target}`;

        if (this.state === 'destination') {
            if (edge.source === this.origin) {
                const d = this.data[routeKey];
                if (!d?.gap) return 'rgba(100,100,100,0.3)';
                if (d.gap.risk === 'high') return '#ef4444';
                if (d.gap.risk === 'moderate') return '#eab308';
                return '#22c55e';
            }
            return 'rgba(200,200,200,0.05)';
        }

        if (this.state === 'comparison') {
            if (routeKey === this.routeKey) return '#fbbf24';
            return 'rgba(200,200,200,0.05)';
        }

        return null;
    }

    renderOverlay(ctx, t) {
        if (this.state !== 'comparison' || !this.origin || !this.dest) return;
        const src = this.viz.projectedNodes.get(this.origin);
        const dst = this.viz.projectedNodes.get(this.dest);
        if (!src || !dst) return;

        ctx.beginPath();
        ctx.moveTo(src.x, src.y);
        ctx.lineTo(dst.x, dst.y);
        ctx.setLineDash([]);
        ctx.strokeStyle = '#f1c40f';
        ctx.lineWidth = 4 / t.k;
        ctx.globalAlpha = 0.9;
        ctx.stroke();
        ctx.globalAlpha = 1;
    }

    // --- state transitions ---

    _setOrigin(code) {
        this.origin = code;
        this.dest = null;
        this.routeKey = null;
        this.state = 'destination';
        this.viz.selectedAirport = code;
        this._renderPanel();
        this.viz.render();
    }

    _setDest(code) {
        this.dest = code;
        this.routeKey = this.origin + '-' + code;
        this.state = 'comparison';
        this.viz.selectedAirport = null;
        this._renderPanel();
        this.viz.render();
    }

    _goBackToDestination() {
        this.dest = null;
        this.routeKey = null;
        this.state = 'destination';
        this.viz.selectedAirport = this.origin;
        this._renderPanel();
        this.viz.render();
    }

    _goBackToOrigin() {
        this.origin = null;
        this.dest = null;
        this.routeKey = null;
        this.state = 'origin';
        this.viz.selectedAirport = null;
        this._renderPanel();
        this.viz.render();
    }

    // --- helpers ---

    _carrierName(code) {
        const names = {
            AA: 'American Airlines', DL: 'Delta Air Lines',
            UA: 'United Airlines',   WN: 'Southwest Airlines',
            B6: 'JetBlue Airways',   AS: 'Alaska Airlines',
            NK: 'Spirit Airlines',   F9: 'Frontier Airlines',
            G4: 'Allegiant Air',     SY: 'Sun Country Airlines',
            HA: 'Hawaiian Airlines', OO: 'SkyWest Airlines',
            MQ: 'Envoy Air',         YX: 'Republic Airways',
            '9E': 'Endeavor Air',    OH: 'PSA Airlines',
            YV: 'Mesa Airlines',     QX: 'Horizon Air',
            PT: 'Piedmont Airlines', ZW: 'Air Wisconsin',
        };
        return names[code] || code;
    }

    _isReachable(code) {
        if (!this.data || !this.origin) return false;
        return !!this.data[this.origin + '-' + code];
    }

    _getReachableDests() {
        if (!this.data || !this.origin) return [];
        const prefix = this.origin + '-';
        const dests = [];
        for (const key of Object.keys(this.data)) {
            if (!key.startsWith(prefix)) continue;
            const dest = key.slice(prefix.length);
            const d = this.data[key];
            const totalFlights = Object.values(d)
                .filter(v => typeof v === 'object' && v.flight_count)
                .reduce((sum, v) => sum + v.flight_count, 0);
            dests.push({ code: dest, flights: totalFlights, gap: d.gap?.gap_pp || 0, risk: d.gap?.risk || null });
        }
        dests.sort((a, b) => b.flights - a.flights);
        return dests;
    }

    _airportName(code) {
        if (!this.viz.data?.nodes) return code;
        const n = this.viz.data.nodes.find(x => x.id === code);
        return n?.name || code;
    }

    // --- panel rendering ---

    _renderPanel() {
        const panel = InfoPanel.panel;
        if (!panel || !this.data) return;
        switch (this.state) {
            case 'origin':      this._renderOriginPanel(panel); break;
            case 'destination': this._renderDestPanel(panel); break;
            case 'comparison':  this._renderComparisonPanel(panel); break;
        }
    }

    _renderOriginPanel(panel) {
        panel.innerHTML = `
            <h2>Carrier Reliability</h2>
            <p>Where are you flying from?</p>
            <div class="chain-search-wrap">
                <input type="text" id="carrier-origin-input" class="chain-search"
                       placeholder="Airport code or name..." autocomplete="off">
                <div id="carrier-origin-ac" class="chain-autocomplete"></div>
            </div>
        `;
        this._setupSearch('carrier-origin-input', 'carrier-origin-ac', (code) => {
            this._setOrigin(code);
        });
    }

    _renderDestPanel(panel) {
        const dests = this._getReachableDests().slice(0, 10);
        const riskColors = { low: '#22c55e', moderate: '#eab308', high: '#ef4444' };

        panel.innerHTML = `
            <div class="chain-nav">
                <button class="chain-nav-btn" id="carrier-back-origin">&larr; Change origin</button>
            </div>
            <h2>From ${this.origin}</h2>
            <p>${this._airportName(this.origin)}</p>
            <h3 style="margin-top:1rem">Where to?</h3>
            <div class="chain-search-wrap">
                <input type="text" id="carrier-dest-input" class="chain-search"
                       placeholder="Destination..." autocomplete="off">
                <div id="carrier-dest-ac" class="chain-autocomplete"></div>
            </div>
            <h3 style="margin-top:1.25rem">Routes from ${this.origin}</h3>
            <ul class="chain-dest-list">
                ${dests.map(d => `
                    <li class="chain-dest-item" data-code="${d.code}">
                        <span class="chain-dest-code">${d.code}</span>
                        <span class="chain-dest-name">${this._airportName(d.code)}</span>
                        ${d.risk ? `<span class="chain-dest-flights" style="color:${riskColors[d.risk]}">${d.gap.toFixed(1)}pp</span>` : ''}
                    </li>
                `).join('')}
            </ul>
        `;

        document.getElementById('carrier-back-origin')
            ?.addEventListener('click', () => this._goBackToOrigin());

        panel.querySelectorAll('.chain-dest-item').forEach(el => {
            el.addEventListener('click', () => this._setDest(el.dataset.code));
        });

        this._setupSearch('carrier-dest-input', 'carrier-dest-ac', (code) => {
            this._setDest(code);
        }, true);
    }

    _renderComparisonPanel(panel) {
        const routeData = this.data[this.routeKey];
        if (!routeData) {
            panel.innerHTML = `
                <div class="chain-nav">
                    <button class="chain-nav-btn" id="carrier-back-dest">&larr; Change route</button>
                </div>
                <h2>${this.origin} &rarr; ${this.dest}</h2>
                <p style="color:var(--text-muted)">No carrier data for this route.</p>
            `;
            document.getElementById('carrier-back-dest')
                ?.addEventListener('click', () => this._goBackToDestination());
            return;
        }

        const carriers = Object.entries(routeData)
            .filter(([key]) => key !== 'gap')
            .sort((a, b) => a[1].pct_delayed - b[1].pct_delayed);

        const riskColor = (pct) => {
            if (pct < 0.15) return { color: '#22c55e', label: 'Low' };
            if (pct < 0.25) return { color: '#eab308', label: 'Moderate' };
            if (pct < 0.40) return { color: '#ef4444', label: 'High' };
            return { color: '#b91c1c', label: 'Severe' };
        };

        panel.innerHTML = `
            <div class="chain-nav">
                <button class="chain-nav-btn" id="carrier-back-dest">&larr; Change route</button>
            </div>
            <h2>${this.origin} &rarr; ${this.dest}</h2>
            <div style="display:grid;gap:0.5rem;margin-top:0.75rem">
                ${carriers.map(([carrier, d]) => {
                    const r = riskColor(d.pct_delayed);
                    return `
                    <div style="background:var(--bg-card);padding:0.75rem;border-radius:6px;border-left:3px solid ${r.color}">
                        <div style="display:flex;justify-content:space-between;align-items:center">
                            <div>
                                <strong>${this._carrierName(carrier)}</strong>
                                <span style="font-size:0.75rem;color:var(--text-muted);margin-left:0.4rem">${carrier}</span>
                            </div>
                            <span style="font-size:0.72rem;font-weight:600;color:${r.color}">${r.label}</span>
                        </div>
                        <div style="display:flex;gap:1rem;margin-top:0.25rem;font-size:0.85rem">
                            <span>${(d.pct_delayed * 100).toFixed(1)}% delayed</span>
                            <span>${d.avg_delay != null ? d.avg_delay.toFixed(1) : '—'} min avg</span>
                            <span>${d.flight_count.toLocaleString()} flights</span>
                        </div>
                    </div>`;
                }).join('')}
            </div>
            ${routeData.gap ? `
                <div style="margin-top:0.75rem;padding:0.75rem;border-left:3px solid var(--risk-high);font-size:0.9rem">
                    <strong>${routeData.gap.gap_pp}pp gap</strong> —
                    ${this._carrierName(routeData.gap.worst_carrier)} is ${routeData.gap.gap_pp} points
                    worse than ${this._carrierName(routeData.gap.best_carrier)} on this route.
                </div>
            ` : ''}
        `;

        document.getElementById('carrier-back-dest')
            ?.addEventListener('click', () => this._goBackToDestination());
    }

    // --- search autocomplete (same pattern as PropagationLayer) ---

    _setupSearch(inputId, dropdownId, onSelect, destOnly = false) {
        const input = document.getElementById(inputId);
        const dropdown = document.getElementById(dropdownId);
        if (!input || !dropdown) return;

        let activeIdx = -1;

        const getMatches = () => {
            const q = input.value.trim().toUpperCase();
            if (q.length < 1) return [];

            let pool;
            if (destOnly) {
                pool = this._getReachableDests().map(d => {
                    const node = this.viz.data?.nodes?.find(n => n.id === d.code);
                    return { id: d.code, name: node?.name || '', flights: d.flights };
                });
            } else {
                pool = (this.viz.data?.nodes || []).map(n => ({
                    id: n.id, name: n.name || '', flights: n.total_flights || 0,
                }));
            }

            return pool.filter(n =>
                n.id.includes(q) || (n.name && n.name.toUpperCase().includes(q))
            ).sort((a, b) => {
                if (a.id === q) return -1;
                if (b.id === q) return 1;
                return b.flights - a.flights;
            }).slice(0, 8);
        };

        const render = () => {
            const matches = getMatches();
            const q = input.value.trim();

            if (q.length < 1) {
                dropdown.innerHTML = '';
                dropdown.style.display = 'none';
                return;
            }

            if (matches.length === 0) {
                dropdown.innerHTML = '<div class="chain-ac-empty">No matches</div>';
                dropdown.style.display = 'block';
                return;
            }

            dropdown.innerHTML = matches.map((m, i) => `
                <div class="chain-ac-item${i === activeIdx ? ' active' : ''}" data-code="${m.id}">
                    <strong>${m.id}</strong>
                    <span class="chain-ac-name">${m.name}</span>
                </div>
            `).join('');
            dropdown.style.display = 'block';

            dropdown.querySelectorAll('.chain-ac-item').forEach(el => {
                el.addEventListener('mousedown', (e) => {
                    e.preventDefault();
                    onSelect(el.dataset.code);
                });
            });
        };

        input.addEventListener('input', () => { activeIdx = -1; render(); });
        input.addEventListener('focus', render);
        input.addEventListener('blur', () => {
            setTimeout(() => { dropdown.style.display = 'none'; }, 150);
        });

        input.addEventListener('keydown', (e) => {
            const items = dropdown.querySelectorAll('.chain-ac-item');
            if (e.key === 'ArrowDown') {
                e.preventDefault();
                activeIdx = Math.min(activeIdx + 1, items.length - 1);
                render();
            } else if (e.key === 'ArrowUp') {
                e.preventDefault();
                activeIdx = Math.max(activeIdx - 1, -1);
                render();
            } else if (e.key === 'Enter') {
                e.preventDefault();
                if (activeIdx >= 0 && items[activeIdx]) {
                    onSelect(items[activeIdx].dataset.code);
                } else if (items.length === 1) {
                    onSelect(items[0].dataset.code);
                }
            } else if (e.key === 'Escape') {
                dropdown.style.display = 'none';
                input.blur();
            }
        });

        setTimeout(() => input.focus(), 50);
    }
}
