/**
 * Weather Sources — CRUD, test, cards.
 */

import { _cachedWeatherSources, weatherSourcesCache } 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_TEST } from '../core/icons.ts';
import * as P from '../core/icon-paths.ts';
import { IconSelect } from '../core/icon-select.ts';
import { wrapCard } from '../core/card-colors.ts';
import { TagInput, renderTagChips } from '../core/tag-input.ts';
import { loadPictureSources } from './streams.ts';
import type { WeatherSource } from '../types.ts';

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

function _getProviderItems() {
    return [
        { value: 'open_meteo', icon: _icon(P.cloudSun), label: 'Open-Meteo', desc: t('weather_source.provider.open_meteo.desc') },
    ];
}

// ── Auto-name ──

let _wsNameManuallyEdited = false;

function _autoGenerateWeatherSourceName() {
    if (_wsNameManuallyEdited) return;
    if ((document.getElementById('weather-source-id') as HTMLInputElement).value) return;
    const provider = (document.getElementById('weather-source-provider') as HTMLSelectElement).value;
    const lat = (document.getElementById('weather-source-latitude') as HTMLInputElement).value;
    const lon = (document.getElementById('weather-source-longitude') as HTMLInputElement).value;
    const providerLabel = provider === 'open_meteo' ? 'Open-Meteo' : provider;
    (document.getElementById('weather-source-name') as HTMLInputElement).value = `${providerLabel} · ${lat}, ${lon}`;
}

// ── Modal ──

let _weatherSourceTagsInput: TagInput | null = null;
let _providerIconSelect: IconSelect | null = null;

class WeatherSourceModal extends Modal {
    constructor() { super('weather-source-modal'); }

    onForceClose() {
        if (_weatherSourceTagsInput) { _weatherSourceTagsInput.destroy(); _weatherSourceTagsInput = null; }
        if (_providerIconSelect) { _providerIconSelect.destroy(); _providerIconSelect = null; }
    }

    snapshotValues() {
        return {
            name: (document.getElementById('weather-source-name') as HTMLInputElement).value,
            provider: (document.getElementById('weather-source-provider') as HTMLSelectElement).value,
            latitude: (document.getElementById('weather-source-latitude') as HTMLInputElement).value,
            longitude: (document.getElementById('weather-source-longitude') as HTMLInputElement).value,
            interval: (document.getElementById('weather-source-interval') as HTMLInputElement).value,
            description: (document.getElementById('weather-source-description') as HTMLInputElement).value,
            tags: JSON.stringify(_weatherSourceTagsInput ? _weatherSourceTagsInput.getValue() : []),
        };
    }
}

const weatherSourceModal = new WeatherSourceModal();

// ── Show / Close ──

export async function showWeatherSourceModal(editData: WeatherSource | null = null): Promise<void> {
    const isEdit = !!editData;
    const titleKey = isEdit ? 'weather_source.edit' : 'weather_source.add';
    document.getElementById('weather-source-modal-title')!.innerHTML = `${ICON_WEATHER} ${t(titleKey)}`;
    (document.getElementById('weather-source-id') as HTMLInputElement).value = editData?.id || '';
    (document.getElementById('weather-source-error') as HTMLElement).style.display = 'none';

    if (isEdit) {
        (document.getElementById('weather-source-name') as HTMLInputElement).value = editData.name || '';
        (document.getElementById('weather-source-provider') as HTMLSelectElement).value = editData.provider || 'open_meteo';
        (document.getElementById('weather-source-latitude') as HTMLInputElement).value = String(editData.latitude ?? 50.0);
        (document.getElementById('weather-source-longitude') as HTMLInputElement).value = String(editData.longitude ?? 0.0);
        (document.getElementById('weather-source-interval') as HTMLInputElement).value = String(editData.update_interval ?? 600);
        document.getElementById('weather-source-interval-display')!.textContent = String(Math.round((editData.update_interval ?? 600) / 60));
        (document.getElementById('weather-source-description') as HTMLInputElement).value = editData.description || '';
    } else {
        (document.getElementById('weather-source-name') as HTMLInputElement).value = '';
        (document.getElementById('weather-source-provider') as HTMLSelectElement).value = 'open_meteo';
        (document.getElementById('weather-source-latitude') as HTMLInputElement).value = '50.0';
        (document.getElementById('weather-source-longitude') as HTMLInputElement).value = '0.0';
        (document.getElementById('weather-source-interval') as HTMLInputElement).value = '600';
        document.getElementById('weather-source-interval-display')!.textContent = '10';
        (document.getElementById('weather-source-description') as HTMLInputElement).value = '';
    }

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

    // Provider IconSelect
    if (_providerIconSelect) { _providerIconSelect.destroy(); _providerIconSelect = null; }
    _providerIconSelect = new IconSelect({
        target: document.getElementById('weather-source-provider') as HTMLSelectElement,
        items: _getProviderItems(),
        columns: 1,
    });

    // Auto-name wiring
    _wsNameManuallyEdited = isEdit;
    (document.getElementById('weather-source-name') as HTMLElement).oninput = () => { _wsNameManuallyEdited = true; };
    (document.getElementById('weather-source-latitude') as HTMLElement).oninput = () => _autoGenerateWeatherSourceName();
    (document.getElementById('weather-source-longitude') as HTMLElement).oninput = () => _autoGenerateWeatherSourceName();
    if (!isEdit) _autoGenerateWeatherSourceName();

    // Show/hide test button based on edit mode
    const testBtn = document.getElementById('weather-source-test-btn');
    if (testBtn) testBtn.style.display = isEdit ? '' : 'none';

    weatherSourceModal.open();
    weatherSourceModal.snapshot();
}

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

// ── Save ──

export async function saveWeatherSource(): Promise<void> {
    const id = (document.getElementById('weather-source-id') as HTMLInputElement).value;
    const name = (document.getElementById('weather-source-name') as HTMLInputElement).value.trim();
    const provider = (document.getElementById('weather-source-provider') as HTMLSelectElement).value;
    const latitude = parseFloat((document.getElementById('weather-source-latitude') as HTMLInputElement).value) || 50.0;
    const longitude = parseFloat((document.getElementById('weather-source-longitude') as HTMLInputElement).value) || 0.0;
    const update_interval = parseInt((document.getElementById('weather-source-interval') as HTMLInputElement).value) || 600;
    const description = (document.getElementById('weather-source-description') as HTMLInputElement).value.trim() || null;

    if (!name) {
        weatherSourceModal.showError(t('weather_source.error.name_required'));
        return;
    }

    const payload = {
        name, provider, latitude, longitude, update_interval, description,
        tags: _weatherSourceTagsInput ? _weatherSourceTagsInput.getValue() : [],
    };

    try {
        const method = id ? 'PUT' : 'POST';
        const url = id ? `/weather-sources/${id}` : '/weather-sources';
        const resp = await fetchWithAuth(url, {
            method,
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(payload),
        });
        if (!resp.ok) {
            const err = await resp.json().catch(() => ({}));
            throw new Error(err.detail || `HTTP ${resp.status}`);
        }
        showToast(t(id ? 'weather_source.updated' : 'weather_source.created'), 'success');
        weatherSourceModal.forceClose();
        weatherSourcesCache.invalidate();
        await loadPictureSources();
    } catch (e: any) {
        if (e.isAuth) return;
        weatherSourceModal.showError(e.message);
    }
}

// ── Edit / Clone / Delete ──

export async function editWeatherSource(sourceId: string): Promise<void> {
    try {
        const resp = await fetchWithAuth(`/weather-sources/${sourceId}`);
        if (!resp.ok) throw new Error(t('weather_source.error.load'));
        const data = await resp.json();
        await showWeatherSourceModal(data);
    } catch (e: any) {
        if (e.isAuth) return;
        showToast(e.message, 'error');
    }
}

export async function cloneWeatherSource(sourceId: string): Promise<void> {
    try {
        const resp = await fetchWithAuth(`/weather-sources/${sourceId}`);
        if (!resp.ok) throw new Error(t('weather_source.error.load'));
        const data = await resp.json();
        delete data.id;
        data.name = data.name + ' (copy)';
        await showWeatherSourceModal(data);
    } catch (e: any) {
        if (e.isAuth) return;
        showToast(e.message, 'error');
    }
}

export async function deleteWeatherSource(sourceId: string): Promise<void> {
    const confirmed = await showConfirm(t('weather_source.delete.confirm'));
    if (!confirmed) return;
    try {
        const resp = await fetchWithAuth(`/weather-sources/${sourceId}`, { method: 'DELETE' });
        if (!resp.ok) {
            const err = await resp.json().catch(() => ({}));
            throw new Error(err.detail || `HTTP ${resp.status}`);
        }
        showToast(t('weather_source.deleted'), 'success');
        weatherSourcesCache.invalidate();
        await loadPictureSources();
    } catch (e: any) {
        if (e.isAuth) return;
        showToast(e.message, 'error');
    }
}

// ── Test (fetch current weather) ──

export async function testWeatherSource(): Promise<void> {
    const id = (document.getElementById('weather-source-id') as HTMLInputElement).value;
    if (!id) return;

    const testBtn = document.getElementById('weather-source-test-btn');
    if (testBtn) testBtn.classList.add('loading');

    try {
        const resp = await fetchWithAuth(`/weather-sources/${id}/test`, { method: 'POST' });
        if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
        const data = await resp.json();
        showToast(`${data.condition} | ${data.temperature.toFixed(1)}\u00B0C | ${data.wind_speed.toFixed(0)} km/h`, 'success');
    } catch (e: any) {
        if (e.isAuth) return;
        showToast(e.message, 'error');
    } finally {
        if (testBtn) testBtn.classList.remove('loading');
    }
}

// ── Geolocation ──

export function weatherSourceGeolocate(): void {
    const btn = document.getElementById('weather-source-geolocate-btn');
    if (!navigator.geolocation) {
        showToast(t('weather_source.geo.not_supported'), 'error');
        return;
    }

    if (btn) btn.classList.add('loading');

    navigator.geolocation.getCurrentPosition(
        (pos) => {
            (document.getElementById('weather-source-latitude') as HTMLInputElement).value = pos.coords.latitude.toFixed(4);
            (document.getElementById('weather-source-longitude') as HTMLInputElement).value = pos.coords.longitude.toFixed(4);
            _autoGenerateWeatherSourceName();
            if (btn) btn.classList.remove('loading');
            showToast(t('weather_source.geo.success'), 'success');
        },
        (err) => {
            if (btn) btn.classList.remove('loading');
            showToast(`${t('weather_source.geo.error')}: ${err.message}`, 'error');
        },
        { timeout: 10000, maximumAge: 60000 }
    );
}

// ── Card rendering ──

export function createWeatherSourceCard(source: WeatherSource) {
    const intervalMin = Math.round(source.update_interval / 60);
    const providerLabel = source.provider === 'open_meteo' ? 'Open-Meteo' : source.provider;

    return wrapCard({
        type: 'template-card',
        dataAttr: 'data-id',
        id: source.id,
        removeOnclick: `deleteWeatherSource('${source.id}')`,
        removeTitle: t('common.delete'),
        content: `
            <div class="template-card-header">
                <div class="template-name">${ICON_WEATHER} ${escapeHtml(source.name)}</div>
            </div>
            <div class="stream-card-props">
                <span class="stream-card-prop">${ICON_WEATHER} ${providerLabel}</span>
                <span class="stream-card-prop" title="${source.latitude.toFixed(2)}, ${source.longitude.toFixed(2)}">
                    <svg class="icon" viewBox="0 0 24 24">${P.mapPin}</svg> ${source.latitude.toFixed(1)}, ${source.longitude.toFixed(1)}
                </span>
                <span class="stream-card-prop">
                    <svg class="icon" viewBox="0 0 24 24">${P.clock}</svg> ${intervalMin}min
                </span>
            </div>
            ${renderTagChips(source.tags)}
            ${source.description ? `<div class="template-config" style="opacity:0.7;">${escapeHtml(source.description)}</div>` : ''}`,
        actions: `
                <button class="btn btn-icon btn-secondary" data-action="test" title="${t('weather_source.test')}">${ICON_TEST}</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 _weatherSourceActions: Record<string, (id: string) => void> = {
    test: (id) => _testWeatherSourceFromCard(id),
    clone: cloneWeatherSource,
    edit: editWeatherSource,
};

async function _testWeatherSourceFromCard(sourceId: string): Promise<void> {
    try {
        const resp = await fetchWithAuth(`/weather-sources/${sourceId}/test`, { method: 'POST' });
        if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
        const data = await resp.json();
        showToast(`${data.condition} | ${data.temperature.toFixed(1)}\u00B0C | ${data.wind_speed.toFixed(0)} km/h`, 'success');
    } catch (e: any) {
        if (e.isAuth) return;
        showToast(e.message, 'error');
    }
}

export function initWeatherSourceDelegation(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="weather-sources"]');
        if (!section) return;
        const card = btn.closest<HTMLElement>('[data-id]');
        if (!card) return;

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

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

// ── Expose to global scope for HTML template onclick handlers ──

window.showWeatherSourceModal = showWeatherSourceModal;
window.closeWeatherSourceModal = closeWeatherSourceModal;
window.saveWeatherSource = saveWeatherSource;
window.editWeatherSource = editWeatherSource;
window.cloneWeatherSource = cloneWeatherSource;
window.deleteWeatherSource = deleteWeatherSource;
window.testWeatherSource = testWeatherSource;
window.weatherSourceGeolocate = weatherSourceGeolocate;
