/**
 * API utilities — base URL, auth headers, fetch wrapper, helpers.
 */

import { apiKey, setApiKey, refreshInterval, setRefreshInterval, displaysCache } from './state.js';
import { t } from './i18n.js';

export const API_BASE = '/api/v1';

export function getHeaders() {
    const headers = {
        'Content-Type': 'application/json'
    };
    if (apiKey) {
        headers['Authorization'] = `Bearer ${apiKey}`;
    }
    return headers;
}

export class ApiError extends Error {
    constructor(status, message) {
        super(message);
        this.name = 'ApiError';
        this.status = status;
        this.isAuth = status === 401;
    }
}

export async function fetchWithAuth(url, options = {}) {
    const { retry = true, timeout = 10000, handle401: auto401 = true, ...fetchOpts } = options;
    const fullUrl = url.startsWith('http') ? url : `${API_BASE}${url}`;
    const headers = fetchOpts.headers
        ? { ...getHeaders(), ...fetchOpts.headers }
        : getHeaders();

    const maxAttempts = retry ? 3 : 1;
    for (let attempt = 0; attempt < maxAttempts; attempt++) {
        const controller = new AbortController();
        if (fetchOpts.signal) {
            fetchOpts.signal.addEventListener('abort', () => controller.abort(), { once: true });
        }
        const timer = setTimeout(() => controller.abort(), timeout);
        try {
            const resp = await fetch(fullUrl, { ...fetchOpts, headers, signal: controller.signal });
            clearTimeout(timer);
            if (resp.status === 401 && auto401) {
                handle401Error();
                throw new ApiError(401, 'Session expired');
            }
            if (resp.status >= 500 && attempt < maxAttempts - 1) {
                await new Promise(r => setTimeout(r, 500 * 2 ** attempt));
                continue;
            }
            return resp;
        } catch (err) {
            clearTimeout(timer);
            if (err instanceof ApiError) throw err;
            if (attempt < maxAttempts - 1) {
                await new Promise(r => setTimeout(r, 500 * 2 ** attempt));
                continue;
            }
            throw err;
        }
    }
}

export function escapeHtml(text) {
    if (!text) return '';
    const div = document.createElement('div');
    div.textContent = text;
    return div.innerHTML;
}

export function isSerialDevice(type) {
    return type === 'adalight' || type === 'ambiled';
}

export function isMockDevice(type) {
    return type === 'mock';
}

export function isMqttDevice(type) {
    return type === 'mqtt';
}

export function isWsDevice(type) {
    return type === 'ws';
}

export function isOpenrgbDevice(type) {
    return type === 'openrgb';
}

export function isDmxDevice(type) {
    return type === 'dmx';
}

export function isEspnowDevice(type) {
    return type === 'espnow';
}

export function isHueDevice(type) {
    return type === 'hue';
}

export function isUsbhidDevice(type) {
    return type === 'usbhid';
}

export function isSpiDevice(type) {
    return type === 'spi';
}

export function isChromaDevice(type) {
    return type === 'chroma';
}

export function isGameSenseDevice(type) {
    return type === 'gamesense';
}

export function handle401Error() {
    if (!apiKey) return; // Already handled or no session
    localStorage.removeItem('wled_api_key');
    setApiKey(null);

    if (refreshInterval) {
        clearInterval(refreshInterval);
        setRefreshInterval(null);
    }

    if (typeof window.updateAuthUI === 'function') {
        window.updateAuthUI();
    }

    const expiredMsg = t('auth.session_expired');

    if (typeof window.showApiKeyModal === 'function') {
        window.showApiKeyModal(expiredMsg, true);
    } else {
        const toast = document.getElementById('toast');
        if (toast) {
            toast.textContent = expiredMsg;
            toast.className = 'toast error show';
            setTimeout(() => { toast.className = 'toast'; }, 3000);
        }
    }
}

let _connCheckTimer = null;
let _serverOnline = null;  // null = unknown, true/false

function _setConnectionState(online) {
    const changed = _serverOnline !== online;
    _serverOnline = online;
    const banner = document.getElementById('connection-overlay');
    const badge = document.getElementById('server-status');
    if (online) {
        if (banner) { banner.style.display = 'none'; banner.setAttribute('aria-hidden', 'true'); }
        if (badge) badge.className = 'status-badge online';
    } else {
        if (banner) { banner.style.display = 'flex'; banner.setAttribute('aria-hidden', 'false'); }
        if (badge) badge.className = 'status-badge offline';
    }
    return changed;
}

export async function loadServerInfo() {
    try {
        const response = await fetch('/health', { signal: AbortSignal.timeout(5000) });
        const data = await response.json();

        document.getElementById('version-number').textContent = `v${data.version}`;
        document.getElementById('server-status').textContent = '●';
        const wasOffline = _serverOnline === false;
        _setConnectionState(true);
        if (wasOffline) {
            // Server came back — reload data
            window.dispatchEvent(new CustomEvent('server:reconnected'));
        }
    } catch (error) {
        console.error('Failed to load server info:', error);
        _setConnectionState(false);
    }
}

/**
 * Start periodic health checks. Shows/hides the connection banner.
 * @param {number} interval - Check interval in ms (default 10s)
 */
export function startConnectionMonitor(interval = 10000) {
    stopConnectionMonitor();
    _connCheckTimer = setInterval(loadServerInfo, interval);
}

export function stopConnectionMonitor() {
    if (_connCheckTimer) {
        clearInterval(_connCheckTimer);
        _connCheckTimer = null;
    }
}

export async function loadDisplays(engineType = null) {
    if (engineType) {
        // Filtered fetch — bypass cache (engine-specific display list)
        try {
            const response = await fetchWithAuth(`/config/displays?engine_type=${engineType}`);
            const data = await response.json();
            if (data.displays && data.displays.length > 0) {
                displaysCache.update(data.displays);
            }
        } catch (error) {
            if (error instanceof ApiError && error.isAuth) return;
            console.error('Failed to load displays:', error);
        }
    } else {
        await displaysCache.fetch();
    }
}

export function configureApiKey() {
    const currentKey = localStorage.getItem('wled_api_key');
    const message = currentKey
        ? t('auth.prompt_update')
        : t('auth.prompt_enter');

    const key = prompt(message);

    if (key === null) {
        return;
    }

    if (key === '') {
        localStorage.removeItem('wled_api_key');
        setApiKey(null);
        document.getElementById('api-key-btn').style.display = 'none';
    } else {
        localStorage.setItem('wled_api_key', key);
        setApiKey(key);
        document.getElementById('api-key-btn').style.display = 'inline-block';
    }

    loadServerInfo();
    loadDisplays();
    document.dispatchEvent(new CustomEvent('auth:keyChanged'));
}
