// Settings → Audio Input row (KL-72, Alpine carve-out KL-133).
// Backend picker + status line + OS-contextual helper. Carved out of
// settings.js. The `loadAudioDevicesInto` helper is shared with
// audio_wizard.js (first-run picker uses the same optgroup layout)
// and `setAudioStatus` is called by mac_audio_modal.js to override
// the status line with friendlier mac_health copy.

// Human-readable group headers, in display order. Keys must match
// the `kind` strings emitted by audio/devices.py so optgroups build
// directly from the API payload.
const KIND_GROUPS = [
    ['wasapi_loopback',  'System audio'],
    ['blackhole',        'System audio'],
    ['pipewire_monitor', 'System audio'],
    ['loopback',         'System audio'],
    ['microphone',       'Microphone'],
    ['line_in',          'Line in'],
    ['other',            'Other inputs'],
];

// Shared loader. Builds the auto-detect option + optgroups inside any
// <select> element. Returns the parsed payload so callers can inspect
// os/current_device for their own helper copy. Used by the Settings
// Audio Input picker AND the first-run audio wizard.
export async function loadAudioDevicesInto(selectEl, opts = {}) {
    if (!selectEl) return null;
    const placeholder = opts.placeholder || 'Auto-detect loopback';
    const data = await fetch('/api/audio/devices').then(r => r.json());
    const devices = data.devices || [];
    selectEl.innerHTML = '';

    // Auto-detect lives outside the optgroups so it stays the obvious
    // first choice even when 30+ inputs are enumerated.
    const autoOpt = document.createElement('option');
    autoOpt.value = 'auto';
    autoOpt.textContent = placeholder;
    selectEl.appendChild(autoOpt);

    // Bucket devices by group label (multiple kinds can share a label
    // — e.g. blackhole + wasapi_loopback both render under "System audio").
    const buckets = new Map();
    for (const [, label] of KIND_GROUPS) buckets.set(label, []);
    for (const dev of devices) {
        const found = KIND_GROUPS.find(([k]) => k === dev.kind);
        const label = found ? found[1] : 'Other inputs';
        buckets.get(label).push(dev);
    }

    for (const [, label] of KIND_GROUPS) {
        // Skip duplicates when multiple kinds collapse onto the same
        // label and we've already emitted that optgroup.
        if (!buckets.has(label)) continue;
        const group = buckets.get(label);
        buckets.delete(label);
        if (!group.length) continue;
        const og = document.createElement('optgroup');
        og.label = label;
        for (const dev of group) {
            const opt = document.createElement('option');
            if (dev.synthetic && dev.backend) {
                opt.value = dev.backend;
            } else {
                opt.value = `device:${dev.name}`;
            }
            // KL-97: hint at the right pick for first-run users. The
            // backend flags exactly one device per OS as recommended;
            // we surface it inline + accent-color it via the CSS rule
            // on .option-recommended.
            const friendly = dev.friendly_name || dev.name;
            if (dev.recommended) {
                opt.textContent = `${friendly} (recommended)`;
                opt.className = 'option-recommended';
            } else {
                opt.textContent = friendly;
            }
            og.appendChild(opt);
        }
        selectEl.appendChild(og);
    }

    selectEl.value = data.backend || 'auto';
    return data;
}

// Shared writer for the Settings → Audio Input status line. Called by
// mac_audio_modal.js to override device-name copy with friendlier
// mac_health state ("✓ System audio is being captured" / "⚠ No
// loopback…"). Updates the Alpine store; falls back to direct DOM
// mutation if Alpine isn't ready yet.
export function setAudioStatus(level, text) {
    const store = window.Alpine?.store('audioInput');
    if (store) {
        store.statusLevel = level || '';
        store.statusText = text || '';
        return;
    }
    const el = document.getElementById('audio-device-status');
    if (el) {
        el.textContent = text;
        el.className = `setting-status ${level || ''}`.trim();
    }
}

// KL-170: debounce dropdown changes so a quick scroll-then-settle
// doesn't trigger one engine rebuild per intermediate option. 250ms is
// long enough to absorb a normal scroll and short enough that the user
// experiences the change as immediate.
const SAVE_DEBOUNCE_MS = 250;
let _saveTimer = null;

function storeDefinition() {
    return {
        statusLevel: '',
        statusText: 'Loading…',
        helperContent: '',
        helperShown: false,

        async loadDevices() {
            const el = document.getElementById('audio-backend-select');
            if (!el) return;
            try {
                const data = await loadAudioDevicesInto(el);
                if (data && data.current_device) {
                    this.statusLevel = 'ok';
                    this.statusText = `✓ Listening on ${data.current_device}`;
                } else {
                    this.statusLevel = 'warn';
                    this.statusText = '⚠ No audio device active';
                }
                this.applyHelper(data);
            } catch (e) {
                this.statusLevel = 'error';
                this.statusText = '✗ Error loading devices';
            }
        },

        // Mac without BlackHole gets a setup-guide nudge; Linux with
        // PipeWire gets reassurance; Windows + Mac-with-BlackHole stay
        // silent so the panel doesn't bury the device list under
        // boilerplate.
        applyHelper(data) {
            if (!data) {
                this.helperShown = false;
                this.helperContent = '';
                return;
            }
            const devices = data.devices || [];
            if (data.os === 'mac') {
                const hasBlackHole = devices.some(d => d.kind === 'blackhole');
                if (hasBlackHole) {
                    this.helperShown = false;
                    this.helperContent = '';
                    return;
                }
                this.helperContent = (
                    'Want Spotify or DJ apps to feed in? '
                    + '<a href="/docs/mac-audio-setup" target="_blank" rel="noopener">Install BlackHole — setup guide →</a>'
                );
                this.helperShown = true;
                return;
            }
            if (data.os === 'linux' && data.pipewire_monitor_available) {
                this.helperContent = 'Picked up automatically from PipeWire — no setup needed.';
                this.helperShown = true;
                return;
            }
            this.helperShown = false;
            this.helperContent = '';
        },

        // Bound to the <select> via x-on:change — sets an optimistic
        // "Saving…" status immediately so the user sees the change took,
        // then debounces the actual POST so a fast scroll-through doesn't
        // hammer the engine with one rebuild per intermediate option.
        scheduleSave() {
            this.statusLevel = 'info';
            this.statusText = 'Saving…';
            if (_saveTimer) clearTimeout(_saveTimer);
            _saveTimer = setTimeout(() => this.save(), SAVE_DEBOUNCE_MS);
        },

        async save() {
            const el = document.getElementById('audio-backend-select');
            if (!el) return;
            const backend = el.value;
            this.statusLevel = 'info';
            this.statusText = 'Saving…';
            try {
                const resp = await fetch('/api/audio/backend', {
                    method: 'POST',
                    headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify({backend}),
                });
                const data = await resp.json();
                if (resp.ok && data.status === 'ok') {
                    this.statusLevel = 'ok';
                    this.statusText = data.device_name
                        ? `✓ Listening on ${data.device_name}`
                        : `✓ Saved: ${backend}`;
                } else {
                    this.statusLevel = 'error';
                    this.statusText = `✗ ${data.error || 'unknown error'}`;
                }
            } catch (e) {
                this.statusLevel = 'error';
                this.statusText = '✗ Network error';
            }
        },
    };
}

function ensureStore() {
    if (!window.Alpine) return null;
    if (!window.Alpine.store('audioInput')) {
        window.Alpine.store('audioInput', storeDefinition());
    }
    return window.Alpine.store('audioInput');
}

if (window.Alpine) {
    ensureStore();
} else {
    document.addEventListener('alpine:init', ensureStore);
}

export function initAudio() {
    let store = ensureStore();
    if (!store) {
        document.addEventListener('alpine:init', () => {
            ensureStore()?.loadDevices();
        }, {once: true});
        return;
    }
    store.loadDevices();
}
