/**
 * HA Light Targets — editor, cards, CRUD for Home Assistant light output targets.
 */

import { _cachedHASources, haSourcesCache, colorStripSourcesCache, outputTargetsCache } from '../core/state.ts';
import { fetchWithAuth, escapeHtml } from '../core/api.ts';
import { t } from '../core/i18n.ts';
import { Modal } from '../core/modal.ts';
import { showToast, showConfirm } from '../core/ui.ts';
import { ICON_CLONE, ICON_EDIT, ICON_START, ICON_STOP, ICON_TRASH } from '../core/icons.ts';
import * as P from '../core/icon-paths.ts';
import { EntitySelect } from '../core/entity-palette.ts';
import { wrapCard } from '../core/card-colors.ts';
import { TagInput, renderTagChips } from '../core/tag-input.ts';
import { getColorStripIcon } from '../core/icons.ts';

const ICON_HA = `<svg class="icon" viewBox="0 0 24 24">${P.home}</svg>`;
const _icon = (d: string) => `<svg class="icon" viewBox="0 0 24 24">${d}</svg>`;

// ── Modal ──

let _haLightTagsInput: TagInput | null = null;
let _haSourceEntitySelect: EntitySelect | null = null;
let _cssSourceEntitySelect: EntitySelect | null = null;
let _mappingEntitySelects: EntitySelect[] = [];
let _editorCssSources: any[] = [];
let _cachedHAEntities: any[] = [];  // fetched from selected HA source

class HALightEditorModal extends Modal {
    constructor() { super('ha-light-editor-modal'); }

    onForceClose() {
        if (_haLightTagsInput) { _haLightTagsInput.destroy(); _haLightTagsInput = null; }
        if (_haSourceEntitySelect) { _haSourceEntitySelect.destroy(); _haSourceEntitySelect = null; }
        if (_cssSourceEntitySelect) { _cssSourceEntitySelect.destroy(); _cssSourceEntitySelect = null; }
        _destroyMappingEntitySelects();
    }

    snapshotValues() {
        return {
            name: (document.getElementById('ha-light-editor-name') as HTMLInputElement).value,
            ha_source: (document.getElementById('ha-light-editor-ha-source') as HTMLSelectElement).value,
            css_source: (document.getElementById('ha-light-editor-css-source') as HTMLSelectElement).value,
            update_rate: (document.getElementById('ha-light-editor-update-rate') as HTMLInputElement).value,
            transition: (document.getElementById('ha-light-editor-transition') as HTMLInputElement).value,
            mappings: _getMappingsJSON(),
            tags: JSON.stringify(_haLightTagsInput ? _haLightTagsInput.getValue() : []),
        };
    }
}

const haLightEditorModal = new HALightEditorModal();

function _destroyMappingEntitySelects(): void {
    for (const es of _mappingEntitySelects) es.destroy();
    _mappingEntitySelects = [];
}

function _getMappingsJSON(): string {
    const rows = document.querySelectorAll('#ha-light-mappings-list .ha-light-mapping-row');
    const mappings: any[] = [];
    rows.forEach(row => {
        mappings.push({
            entity_id: (row.querySelector('.ha-mapping-entity') as HTMLSelectElement).value.trim(),
            led_start: parseInt((row.querySelector('.ha-mapping-led-start') as HTMLInputElement).value) || 0,
            led_end: parseInt((row.querySelector('.ha-mapping-led-end') as HTMLInputElement).value) || -1,
            brightness_scale: parseFloat((row.querySelector('.ha-mapping-brightness') as HTMLInputElement).value) || 1.0,
        });
    });
    return JSON.stringify(mappings);
}

function _getEntityItems() {
    return _cachedHAEntities
        .filter((e: any) => e.domain === 'light')
        .map((e: any) => ({
            value: e.entity_id,
            label: e.friendly_name || e.entity_id,
            icon: _icon(P.lightbulb),
            desc: e.state || '',
        }));
}

async function _fetchHAEntities(haSourceId: string): Promise<void> {
    if (!haSourceId) { _cachedHAEntities = []; return; }
    try {
        const resp = await fetchWithAuth(`/home-assistant/sources/${haSourceId}/entities`);
        if (!resp.ok) { _cachedHAEntities = []; return; }
        const data = await resp.json();
        _cachedHAEntities = data.entities || [];
    } catch {
        _cachedHAEntities = [];
    }
}

function _rebuildMappingEntityOptions(): void {
    // Update all existing mapping entity <select> elements with new options
    const lightEntities = _cachedHAEntities.filter((e: any) => e.domain === 'light');
    const rows = document.querySelectorAll('#ha-light-mappings-list .ha-light-mapping-row');
    rows.forEach(row => {
        const sel = row.querySelector('.ha-mapping-entity') as HTMLSelectElement;
        if (!sel) return;
        const currentVal = sel.value;
        sel.innerHTML = `<option value="">${t('ha_light.mapping.select_entity')}</option>` +
            lightEntities.map((e: any) =>
                `<option value="${e.entity_id}" ${e.entity_id === currentVal ? 'selected' : ''}>${escapeHtml(e.friendly_name || e.entity_id)}</option>`
            ).join('');
        // Restore value if it was set but not in list
        if (currentVal && !lightEntities.some((e: any) => e.entity_id === currentVal)) {
            sel.innerHTML += `<option value="${escapeHtml(currentVal)}" selected>${escapeHtml(currentVal)}</option>`;
        }
    });
    // Rebuild EntitySelect instances (destroy old, create new)
    _destroyMappingEntitySelects();
    rows.forEach(row => {
        const sel = row.querySelector('.ha-mapping-entity') as HTMLSelectElement;
        if (!sel) return;
        const es = new EntitySelect({
            target: sel,
            getItems: _getEntityItems,
            placeholder: t('ha_light.mapping.search_entity'),
        });
        _mappingEntitySelects.push(es);
    });
}

// ── Mapping rows ──

export function addHALightMapping(data: any = null): void {
    const list = document.getElementById('ha-light-mappings-list');
    if (!list) return;

    const idx = list.querySelectorAll('.ha-light-mapping-row').length + 1;
    const row = document.createElement('div');
    row.className = 'ha-light-mapping-row';

    // Build options from cached entities (light domain only)
    const lightEntities = _cachedHAEntities.filter((e: any) => e.domain === 'light');
    const selectedId = data?.entity_id || '';
    const entityOptions = `<option value="">${t('ha_light.mapping.select_entity')}</option>` +
        lightEntities.map((e: any) =>
            `<option value="${e.entity_id}" ${e.entity_id === selectedId ? 'selected' : ''}>${escapeHtml(e.friendly_name || e.entity_id)}</option>`
        ).join('');
    // If editing and the entity isn't in the list (HA disconnected), add it manually
    const hasSelected = !selectedId || lightEntities.some((e: any) => e.entity_id === selectedId);
    const extraOption = (!hasSelected && selectedId)
        ? `<option value="${escapeHtml(selectedId)}" selected>${escapeHtml(selectedId)}</option>`
        : '';

    row.innerHTML = `
        <div class="ha-mapping-header">
            <span class="ha-mapping-label">${_icon(P.lightbulb)} #${idx}</span>
            <button type="button" class="btn-remove-mapping" onclick="removeHALightMapping(this)" title="${t('common.delete')}">${ICON_TRASH}</button>
        </div>
        <div class="ha-mapping-fields">
            <div class="ha-mapping-field">
                <label>${t('ha_light.mapping.entity_id')}</label>
                <select class="ha-mapping-entity">${entityOptions}${extraOption}</select>
            </div>
            <div class="ha-mapping-range-row">
                <div>
                    <label>${t('ha_light.mapping.led_start')}</label>
                    <input type="number" class="ha-mapping-led-start" value="${data?.led_start ?? 0}" min="0" step="1">
                </div>
                <div>
                    <label>${t('ha_light.mapping.led_end')}</label>
                    <input type="number" class="ha-mapping-led-end" value="${data?.led_end ?? -1}" min="-1" step="1">
                </div>
                <div>
                    <label>${t('ha_light.mapping.brightness')}</label>
                    <input type="number" class="ha-mapping-brightness" value="${data?.brightness_scale ?? 1.0}" min="0" max="1" step="0.1">
                </div>
            </div>
        </div>
    `;
    list.appendChild(row);

    // Attach EntitySelect to the entity dropdown
    const entitySelect = row.querySelector('.ha-mapping-entity') as HTMLSelectElement;
    const es = new EntitySelect({
        target: entitySelect,
        getItems: _getEntityItems,
        placeholder: t('ha_light.mapping.search_entity'),
    });
    _mappingEntitySelects.push(es);
}

export function removeHALightMapping(btn: HTMLElement): void {
    const row = btn.closest('.ha-light-mapping-row');
    if (!row) return;
    // Find and destroy the EntitySelect for this row
    const select = row.querySelector('.ha-mapping-entity') as HTMLSelectElement;
    if (select) {
        const idx = _mappingEntitySelects.findIndex(es => (es as any)._target === select || (es as any).target === select);
        if (idx >= 0) {
            _mappingEntitySelects[idx].destroy();
            _mappingEntitySelects.splice(idx, 1);
        }
    }
    row.remove();
}

// ── Show / Close ──

export async function showHALightEditor(targetId: string | null = null, cloneData: any = null): Promise<void> {
    // Load data for dropdowns
    const [haSources, cssSources] = await Promise.all([
        haSourcesCache.fetch().catch((): any[] => []),
        colorStripSourcesCache.fetch().catch((): any[] => []),
    ]);
    _editorCssSources = cssSources;

    const isEdit = !!targetId;
    const isClone = !!cloneData;
    const titleKey = isEdit ? 'ha_light.edit' : 'ha_light.add';
    document.getElementById('ha-light-editor-title')!.innerHTML = `${ICON_HA} ${t(titleKey)}`;
    (document.getElementById('ha-light-editor-id') as HTMLInputElement).value = '';
    (document.getElementById('ha-light-editor-error') as HTMLElement).style.display = 'none';

    // Populate HA source dropdown
    const haSelect = document.getElementById('ha-light-editor-ha-source') as HTMLSelectElement;
    haSelect.innerHTML = haSources.map((s: any) =>
        `<option value="${s.id}">${escapeHtml(s.name)}</option>`
    ).join('');

    // Populate CSS source dropdown
    const cssSelect = document.getElementById('ha-light-editor-css-source') as HTMLSelectElement;
    cssSelect.innerHTML = `<option value="">—</option>` + cssSources.map((s: any) =>
        `<option value="${s.id}">${escapeHtml(s.name)}</option>`
    ).join('');

    // Clear mappings
    _destroyMappingEntitySelects();
    document.getElementById('ha-light-mappings-list')!.innerHTML = '';

    let editData: any = null;

    if (isEdit) {
        try {
            const resp = await fetchWithAuth(`/output-targets/${targetId}`);
            if (!resp.ok) throw new Error('Failed to load target');
            editData = await resp.json();
        } catch (e: any) {
            if (e.isAuth) return;
            showToast(e.message, 'error');
            return;
        }
    } else if (isClone) {
        editData = cloneData;
    }

    if (editData) {
        if (isEdit) (document.getElementById('ha-light-editor-id') as HTMLInputElement).value = editData.id;
        (document.getElementById('ha-light-editor-name') as HTMLInputElement).value = editData.name || '';
        haSelect.value = editData.ha_source_id || '';
        cssSelect.value = editData.color_strip_source_id || '';
        (document.getElementById('ha-light-editor-update-rate') as HTMLInputElement).value = String(editData.update_rate ?? 2.0);
        document.getElementById('ha-light-editor-update-rate-display')!.textContent = (editData.update_rate ?? 2.0).toFixed(1);
        (document.getElementById('ha-light-editor-transition') as HTMLInputElement).value = String(editData.ha_transition ?? 0.5);
        document.getElementById('ha-light-editor-transition-display')!.textContent = (editData.ha_transition ?? 0.5).toFixed(1);
        (document.getElementById('ha-light-editor-description') as HTMLInputElement).value = editData.description || '';

        // Fetch entities from the selected HA source before loading mappings
        await _fetchHAEntities(editData.ha_source_id || '');

        // Load mappings (with entity picker populated)
        const mappings = editData.ha_light_mappings || [];
        mappings.forEach((m: any) => addHALightMapping(m));
    } else {
        (document.getElementById('ha-light-editor-name') as HTMLInputElement).value = '';
        (document.getElementById('ha-light-editor-update-rate') as HTMLInputElement).value = '2.0';
        document.getElementById('ha-light-editor-update-rate-display')!.textContent = '2.0';
        (document.getElementById('ha-light-editor-transition') as HTMLInputElement).value = '0.5';
        document.getElementById('ha-light-editor-transition-display')!.textContent = '0.5';
        (document.getElementById('ha-light-editor-description') as HTMLInputElement).value = '';

        // Fetch entities from the first HA source
        const firstSource = haSources[0]?.id || '';
        await _fetchHAEntities(firstSource);

        // Add one empty mapping by default
        addHALightMapping();
    }

    // EntitySelects
    if (_haSourceEntitySelect) { _haSourceEntitySelect.destroy(); _haSourceEntitySelect = null; }
    _haSourceEntitySelect = new EntitySelect({
        target: haSelect,
        getItems: () => haSources.map((s: any) => ({
            value: s.id, label: s.name, icon: ICON_HA,
            desc: s.connected ? t('ha_source.connected') : t('ha_source.disconnected'),
        })),
        placeholder: t('palette.search'),
        onChange: async (newSourceId: string) => {
            // Refetch entities when HA source changes, then rebuild mapping selects
            await _fetchHAEntities(newSourceId);
            _rebuildMappingEntityOptions();
        },
    });

    if (_cssSourceEntitySelect) { _cssSourceEntitySelect.destroy(); _cssSourceEntitySelect = null; }
    _cssSourceEntitySelect = new EntitySelect({
        target: cssSelect,
        getItems: () => _editorCssSources.map((s: any) => ({
            value: s.id, label: s.name, icon: getColorStripIcon(s.source_type), desc: s.source_type,
        })),
        placeholder: t('palette.search'),
    });

    // Tags
    if (_haLightTagsInput) { _haLightTagsInput.destroy(); _haLightTagsInput = null; }
    _haLightTagsInput = new TagInput(document.getElementById('ha-light-tags-container'), { placeholder: t('tags.placeholder') });
    _haLightTagsInput.setValue(editData?.tags || []);

    haLightEditorModal.open();
    haLightEditorModal.snapshot();
}

export async function closeHALightEditor(): Promise<void> {
    await haLightEditorModal.close();
}

// ── Save ──

export async function saveHALightEditor(): Promise<void> {
    const targetId = (document.getElementById('ha-light-editor-id') as HTMLInputElement).value;
    const name = (document.getElementById('ha-light-editor-name') as HTMLInputElement).value.trim();
    const haSourceId = (document.getElementById('ha-light-editor-ha-source') as HTMLSelectElement).value;
    const cssSourceId = (document.getElementById('ha-light-editor-css-source') as HTMLSelectElement).value;
    const updateRate = parseFloat((document.getElementById('ha-light-editor-update-rate') as HTMLInputElement).value) || 2.0;
    const transition = parseFloat((document.getElementById('ha-light-editor-transition') as HTMLInputElement).value) || 0.5;
    const description = (document.getElementById('ha-light-editor-description') as HTMLInputElement).value.trim() || null;

    if (!name) {
        haLightEditorModal.showError(t('ha_light.error.name_required'));
        return;
    }
    if (!haSourceId) {
        haLightEditorModal.showError(t('ha_light.error.ha_source_required'));
        return;
    }

    // Collect mappings
    const mappings = JSON.parse(_getMappingsJSON()).filter((m: any) => m.entity_id);

    const payload: any = {
        name,
        ha_source_id: haSourceId,
        color_strip_source_id: cssSourceId,
        ha_light_mappings: mappings,
        update_rate: updateRate,
        transition,
        description,
        tags: _haLightTagsInput ? _haLightTagsInput.getValue() : [],
    };

    try {
        let response;
        if (targetId) {
            response = await fetchWithAuth(`/output-targets/${targetId}`, {
                method: 'PUT',
                body: JSON.stringify(payload),
            });
        } else {
            payload.target_type = 'ha_light';
            response = await fetchWithAuth('/output-targets', {
                method: 'POST',
                body: JSON.stringify(payload),
            });
        }

        if (!response.ok) {
            const err = await response.json().catch(() => ({}));
            throw new Error(err.detail || `HTTP ${response.status}`);
        }

        showToast(targetId ? t('ha_light.updated') : t('ha_light.created'), 'success');
        outputTargetsCache.invalidate();
        haLightEditorModal.forceClose();
        // Reload targets tab
        if (window.loadTargetsTab) await window.loadTargetsTab();
    } catch (e: any) {
        if (e.isAuth) return;
        haLightEditorModal.showError(e.message);
    }
}

// ── Edit / Clone / Delete ──

export async function editHALightTarget(targetId: string): Promise<void> {
    await showHALightEditor(targetId);
}

export async function cloneHALightTarget(targetId: string): Promise<void> {
    try {
        const resp = await fetchWithAuth(`/output-targets/${targetId}`);
        if (!resp.ok) throw new Error('Failed to load target');
        const data = await resp.json();
        delete data.id;
        data.name = data.name + ' (copy)';
        await showHALightEditor(null, data);
    } catch (e: any) {
        if (e.isAuth) return;
        showToast(e.message, 'error');
    }
}

// ── Card rendering ──

export function createHALightTargetCard(target: any, haSourceMap: Record<string, any> = {}, cssSourceMap: Record<string, any> = {}): string {
    const haSource = haSourceMap[target.ha_source_id];
    const cssSource = cssSourceMap[target.color_strip_source_id];
    const haName = haSource ? escapeHtml(haSource.name) : target.ha_source_id || '—';
    const cssName = cssSource ? escapeHtml(cssSource.name) : target.color_strip_source_id || '—';
    const mappingCount = target.ha_light_mappings?.length || 0;
    const isRunning = target.state?.processing;

    return wrapCard({
        type: 'card',
        dataAttr: 'data-ha-target-id',
        id: target.id,
        removeOnclick: `deleteTarget('${target.id}')`,
        removeTitle: t('common.delete'),
        content: `
            <div class="card-header">
                <span class="card-title-text">${ICON_HA} ${escapeHtml(target.name)}</span>
            </div>
            <div class="stream-card-props">
                <span class="stream-card-prop">${ICON_HA} ${haName}</span>
                ${cssName !== '—' ? `<span class="stream-card-prop">${_icon(P.palette)} ${cssName}</span>` : ''}
                <span class="stream-card-prop">${_icon(P.listChecks)} ${mappingCount} light${mappingCount !== 1 ? 's' : ''}</span>
                <span class="stream-card-prop">${_icon(P.clock)} ${target.update_rate ?? 2.0} Hz</span>
            </div>
            ${renderTagChips(target.tags || [])}
            ${target.description ? `<div class="template-config" style="opacity:0.7;">${escapeHtml(target.description)}</div>` : ''}`,
        actions: `
                <button class="btn btn-icon ${isRunning ? 'btn-danger' : 'btn-primary'}" data-action="${isRunning ? 'stop' : 'start'}" title="${isRunning ? t('targets.stop') : t('targets.start')}">
                    ${isRunning ? ICON_STOP : ICON_START}
                </button>
                <button class="btn btn-icon btn-secondary" data-action="clone" title="${t('common.clone')}">${ICON_CLONE}</button>
                <button class="btn btn-icon btn-secondary" data-action="edit" title="${t('common.edit')}">${ICON_EDIT}</button>`,
    });
}

// ── Event delegation ──

const _haLightActions: Record<string, (id: string) => void> = {
    start: (id) => _startStop(id, 'start'),
    stop: (id) => _startStop(id, 'stop'),
    clone: cloneHALightTarget,
    edit: editHALightTarget,
};

async function _startStop(targetId: string, action: 'start' | 'stop'): Promise<void> {
    try {
        const resp = await fetchWithAuth(`/output-targets/${targetId}/${action}`, { method: 'POST' });
        if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
        outputTargetsCache.invalidate();
        if (window.loadTargetsTab) await window.loadTargetsTab();
    } catch (e: any) {
        if (e.isAuth) return;
        showToast(e.message, 'error');
    }
}

export function initHALightTargetDelegation(container: HTMLElement): void {
    container.addEventListener('click', (e: MouseEvent) => {
        const btn = (e.target as HTMLElement).closest<HTMLElement>('[data-action]');
        if (!btn) return;

        const section = btn.closest<HTMLElement>('[data-card-section="ha-light-targets"]');
        if (!section) return;
        const card = btn.closest<HTMLElement>('[data-ha-target-id]');
        if (!card) return;

        const action = btn.dataset.action;
        const id = card.getAttribute('data-ha-target-id');
        if (!action || !id) return;

        const handler = _haLightActions[action];
        if (handler) {
            e.stopPropagation();
            handler(id);
        }
    });
}

// ── Expose to global scope ──

window.showHALightEditor = showHALightEditor;
window.closeHALightEditor = closeHALightEditor;
window.saveHALightEditor = saveHALightEditor;
window.editHALightTarget = editHALightTarget;
window.cloneHALightTarget = cloneHALightTarget;
window.addHALightMapping = addHALightMapping;
window.removeHALightMapping = removeHALightMapping;
