/**
 * Shared mutable state — all global variables live here.
 *
 * ES module `export let` creates live bindings: importers always see
 * the latest value.  But importers cannot reassign, so every variable
 * gets a setter function.
 */

import { DataCache } from './cache.ts';
import type {
    Device, OutputTarget, ColorStripSource, PatternTemplate,
    ValueSource, AudioSource, PictureSource, ScenePreset,
    SyncClock, WeatherSource, HomeAssistantSource, MQTTSource, Asset, Automation, Display, FilterDef, EngineInfo,
    CaptureTemplate, PostprocessingTemplate, AudioTemplate,
    ColorStripProcessingTemplate, FilterInstance, KeyColorRectangle,
    GameIntegration, GameAdapterInfo,
} from '../types.ts';

export let apiKey: string | null = null;
export function setApiKey(v: string | null) { apiKey = v; }

export let authRequired = true;
export function setAuthRequired(v: boolean) { authRequired = v; }

export let refreshInterval: ReturnType<typeof setInterval> | null = null;
export function setRefreshInterval(v: ReturnType<typeof setInterval> | null) { refreshInterval = v; }

export let _cachedDisplays: Display[] | null = null;

export let _displayPickerCallback: ((index: number, display?: Display | null) => void) | null = null;
export function set_displayPickerCallback(v: ((index: number, display?: Display | null) => void) | null) { _displayPickerCallback = v; }

export let _displayPickerSelectedIndex: number | null = null;
export function set_displayPickerSelectedIndex(v: number | null) { _displayPickerSelectedIndex = v; }

// Calibration
export const calibrationTestState: Record<string, Set<string>> = {};

export const EDGE_TEST_COLORS: Record<string, number[]> = {
    top: [255, 0, 0],
    right: [0, 255, 0],
    bottom: [0, 100, 255],
    left: [255, 255, 0]
};

// Track logged errors to avoid console spam
export const loggedErrors = new Map<string, boolean>();

// Device brightness cache
export let _deviceBrightnessCache: Record<string, number> = {};
export function set_deviceBrightnessCache(v: Record<string, number>) { _deviceBrightnessCache = v; }
export function updateDeviceBrightness(deviceId: string, value: number) {
    _deviceBrightnessCache = { ..._deviceBrightnessCache, [deviceId]: value };
}

// Discovery state
export let _discoveryScanRunning = false;
export function set_discoveryScanRunning(v: boolean) { _discoveryScanRunning = v; }

export let _discoveryCache: Record<string, any[]> = {};
export function set_discoveryCache(v: Record<string, any[]>) { _discoveryCache = v; }

// Streams / templates state
export let _cachedStreams: PictureSource[] = [];
export let _cachedPPTemplates: PostprocessingTemplate[] = [];
export let _cachedCaptureTemplates: CaptureTemplate[] = [];
export let _availableFilters: FilterDef[] = [];

export let availableEngines: EngineInfo[] = [];
export function setAvailableEngines(v: EngineInfo[]) { availableEngines = v; }

export let currentEditingTemplateId: string | null = null;
export function setCurrentEditingTemplateId(v: string | null) { currentEditingTemplateId = v; }

export let _streamNameManuallyEdited = false;
export function set_streamNameManuallyEdited(v: boolean) { _streamNameManuallyEdited = v; }

export let _streamModalPPTemplates: PostprocessingTemplate[] = [];
export function set_streamModalPPTemplates(v: PostprocessingTemplate[]) { _streamModalPPTemplates = v; }

export let _templateNameManuallyEdited = false;
export function set_templateNameManuallyEdited(v: boolean) { _templateNameManuallyEdited = v; }

// PP template state
export let _modalFilters: FilterInstance[] = [];
export function set_modalFilters(v: FilterInstance[]) { _modalFilters = v; }

export let _ppTemplateNameManuallyEdited = false;
export function set_ppTemplateNameManuallyEdited(v: boolean) { _ppTemplateNameManuallyEdited = v; }

// CSPT (Color Strip Processing Template) state
export let _csptModalFilters: FilterInstance[] = [];
export function set_csptModalFilters(v: FilterInstance[]) { _csptModalFilters = v; }

export let _csptNameManuallyEdited = false;
export function set_csptNameManuallyEdited(v: boolean) { _csptNameManuallyEdited = v; }

export let _stripFilters: FilterDef[] = [];

export let _cachedCSPTemplates: ColorStripProcessingTemplate[] = [];

// Stream test state
export let currentTestingTemplate: CaptureTemplate | null = null;
export function setCurrentTestingTemplate(v: CaptureTemplate | null) { currentTestingTemplate = v; }

export let _currentTestStreamId: string | null = null;
export function set_currentTestStreamId(v: string | null) { _currentTestStreamId = v; }

export let _currentTestPPTemplateId: string | null = null;
export function set_currentTestPPTemplateId(v: string | null) { _currentTestPPTemplateId = v; }

export let _lastValidatedImageSource = '';
export function set_lastValidatedImageSource(v: string) { _lastValidatedImageSource = v; }

// Target editor state
export let _targetEditorDevices: Device[] = [];
export function set_targetEditorDevices(v: Device[]) { _targetEditorDevices = v; }

// LED Preview WebSockets
export const ledPreviewWebSockets: Record<string, WebSocket> = {};

// Tutorial state
export interface TutorialState {
    steps: { selector: string; textKey: string; position: string; global?: boolean }[];
    overlay: HTMLElement;
    mode: string;
    step: number;
    resolveTarget: (step: { selector: string; textKey: string; position: string; global?: boolean }) => Element | null;
    container: Element | null;
    onClose: (() => void) | null;
}
export let activeTutorial: TutorialState | null = null;
export function setActiveTutorial(v: TutorialState | null) { activeTutorial = v; }

// Confirm modal
export let confirmResolve: ((value: boolean) => void) | null = null;
export function setConfirmResolve(v: ((value: boolean) => void) | null) { confirmResolve = v; }

// Loading guards
export let _dashboardLoading = false;
export function set_dashboardLoading(v: boolean) { _dashboardLoading = v; }

export let _sourcesLoading = false;
export function set_sourcesLoading(v: boolean) { _sourcesLoading = v; }

export let _automationsLoading = false;
export function set_automationsLoading(v: boolean) { _automationsLoading = v; }

// Dashboard poll interval (ms), persisted in localStorage
const _POLL_KEY = 'dashboard_poll_interval';
const _POLL_DEFAULT = 2000;
export let dashboardPollInterval = parseInt(localStorage.getItem(_POLL_KEY) as string, 10) || _POLL_DEFAULT;
export function setDashboardPollInterval(v: number) {
    dashboardPollInterval = v;
    localStorage.setItem(_POLL_KEY, String(v));
}

// Pattern template editor state
export let patternEditorRects: KeyColorRectangle[] = [];
export function setPatternEditorRects(v: KeyColorRectangle[]) { patternEditorRects = v; }

export let patternEditorSelectedIdx = -1;
export function setPatternEditorSelectedIdx(v: number) { patternEditorSelectedIdx = v; }

export let patternEditorBgImage: HTMLImageElement | null = null;
export function setPatternEditorBgImage(v: HTMLImageElement | null) { patternEditorBgImage = v; }

export let patternCanvasDragMode: string | null = null;
export function setPatternCanvasDragMode(v: string | null) { patternCanvasDragMode = v; }

export let patternCanvasDragStart: { x?: number; y?: number; mx?: number; my?: number } | null = null;
export function setPatternCanvasDragStart(v: { x?: number; y?: number; mx?: number; my?: number } | null) { patternCanvasDragStart = v; }

export let patternCanvasDragOrigRect: KeyColorRectangle | null = null;
export function setPatternCanvasDragOrigRect(v: KeyColorRectangle | null) { patternCanvasDragOrigRect = v; }

export let patternEditorHoveredIdx = -1;
export function setPatternEditorHoveredIdx(v: number) { patternEditorHoveredIdx = v; }

export let patternEditorHoverHit: string | null = null;
export function setPatternEditorHoverHit(v: string | null) { patternEditorHoverHit = v; }

export const PATTERN_RECT_COLORS = [
    'rgba(76,175,80,0.35)', 'rgba(33,150,243,0.35)', 'rgba(255,152,0,0.35)',
    'rgba(156,39,176,0.35)', 'rgba(0,188,212,0.35)', 'rgba(244,67,54,0.35)',
    'rgba(255,235,59,0.35)', 'rgba(121,85,72,0.35)',
];
export const PATTERN_RECT_BORDERS = [
    '#4CAF50', '#2196F3', '#FF9800', '#9C27B0', '#00BCD4', '#F44336', '#FFEB3B', '#795548',
];

// Audio sources
export let _cachedAudioSources: AudioSource[] = [];
export let _cachedAudioTemplates: AudioTemplate[] = [];

export let availableAudioEngines: EngineInfo[] = [];
export function setAvailableAudioEngines(v: EngineInfo[]) { availableAudioEngines = v; }

export let currentEditingAudioTemplateId: string | null = null;
export function setCurrentEditingAudioTemplateId(v: string | null) { currentEditingAudioTemplateId = v; }

export let _audioTemplateNameManuallyEdited = false;
export function set_audioTemplateNameManuallyEdited(v: boolean) { _audioTemplateNameManuallyEdited = v; }

// Audio processing templates
export let _cachedAudioProcessingTemplates: any[] = [];
export let _cachedAudioFilterDefs: any[] = [];

// Value sources
export let _cachedValueSources: ValueSource[] = [];

// Sync clocks
export let _cachedSyncClocks: SyncClock[] = [];
export let _cachedWeatherSources: WeatherSource[] = [];
export let _cachedHASources: HomeAssistantSource[] = [];
export let _cachedAssets: Asset[] = [];

// Automations
export let _automationsCache: Automation[] | null = null;

// ─── DataCache instances ───────────────────────────────────────────
// Each cache syncs its data into the existing `export let` variable
// via a subscriber, preserving backward compatibility.

export const displaysCache = new DataCache<Display[] | null>({
    endpoint: '/config/displays',
    extractData: json => json.displays || [],
    defaultValue: null,
});
displaysCache.subscribe(v => { _cachedDisplays = v; });

export const streamsCache = new DataCache<PictureSource[]>({
    endpoint: '/picture-sources',
    extractData: json => json.streams || [],
});
streamsCache.subscribe(v => { _cachedStreams = v; });

export const ppTemplatesCache = new DataCache<PostprocessingTemplate[]>({
    endpoint: '/postprocessing-templates',
    extractData: json => json.templates || [],
});
ppTemplatesCache.subscribe(v => { _cachedPPTemplates = v; });

export const captureTemplatesCache = new DataCache<CaptureTemplate[]>({
    endpoint: '/capture-templates',
    extractData: json => json.templates || [],
});
captureTemplatesCache.subscribe(v => { _cachedCaptureTemplates = v; });

export const audioSourcesCache = new DataCache<AudioSource[]>({
    endpoint: '/audio-sources',
    extractData: json => json.sources || [],
});
audioSourcesCache.subscribe(v => { _cachedAudioSources = v; });

export const audioTemplatesCache = new DataCache<AudioTemplate[]>({
    endpoint: '/audio-templates',
    extractData: json => json.templates || [],
});
audioTemplatesCache.subscribe(v => { _cachedAudioTemplates = v; });

export const valueSourcesCache = new DataCache<ValueSource[]>({
    endpoint: '/value-sources',
    extractData: json => json.sources || [],
});
valueSourcesCache.subscribe(v => { _cachedValueSources = v; });

export const syncClocksCache = new DataCache<SyncClock[]>({
    endpoint: '/sync-clocks',
    extractData: json => json.clocks || [],
});
syncClocksCache.subscribe(v => { _cachedSyncClocks = v; });

export const weatherSourcesCache = new DataCache<WeatherSource[]>({
    endpoint: '/weather-sources',
    extractData: json => json.sources || [],
});
weatherSourcesCache.subscribe(v => { _cachedWeatherSources = v; });

export const haSourcesCache = new DataCache<HomeAssistantSource[]>({
    endpoint: '/home-assistant/sources',
    extractData: json => json.sources || [],
});
haSourcesCache.subscribe(v => { _cachedHASources = v; });

export let _cachedMQTTSources: MQTTSource[] = [];

export const mqttSourcesCache = new DataCache<MQTTSource[]>({
    endpoint: '/mqtt/sources',
    extractData: json => json.sources || [],
});
mqttSourcesCache.subscribe(v => { _cachedMQTTSources = v; });

export const assetsCache = new DataCache<Asset[]>({
    endpoint: '/assets',
    extractData: json => json.assets || [],
});
assetsCache.subscribe(v => { _cachedAssets = v; });

export const filtersCache = new DataCache<FilterDef[]>({
    endpoint: '/filters',
    extractData: json => json.filters || [],
});
filtersCache.subscribe(v => { _availableFilters = v; });

export const automationsCacheObj = new DataCache<Automation[]>({
    endpoint: '/automations',
    extractData: json => json.automations || [],
});
automationsCacheObj.subscribe(v => { _automationsCache = v; });

export let _cachedColorStripSources: ColorStripSource[] = [];
export const colorStripSourcesCache = new DataCache<ColorStripSource[]>({
    endpoint: '/color-strip-sources',
    extractData: json => json.sources || [],
});
colorStripSourcesCache.subscribe(v => { _cachedColorStripSources = v; });

export const csptCache = new DataCache<ColorStripProcessingTemplate[]>({
    endpoint: '/color-strip-processing-templates',
    extractData: json => json.templates || [],
});
csptCache.subscribe(v => { _cachedCSPTemplates = v; });

export const stripFiltersCache = new DataCache<FilterDef[]>({
    endpoint: '/strip-filters',
    extractData: json => json.filters || [],
});
stripFiltersCache.subscribe(v => { _stripFilters = v; });

export const devicesCache = new DataCache<Device[]>({
    endpoint: '/devices',
    extractData: json => json.devices || [],
});

export const outputTargetsCache = new DataCache<OutputTarget[]>({
    endpoint: '/output-targets',
    extractData: json => json.targets || [],
});

export const patternTemplatesCache = new DataCache<PatternTemplate[]>({
    endpoint: '/pattern-templates',
    extractData: json => json.templates || [],
});

export const scenePresetsCache = new DataCache<ScenePreset[]>({
    endpoint: '/scene-presets',
    extractData: json => json.presets || [],
});

export interface GradientEntity {
    id: string;
    name: string;
    stops: Array<{ position: number; color: number[] }>;
    is_builtin: boolean;
    description?: string;
    tags: string[];
}

export const gradientsCache = new DataCache<GradientEntity[]>({
    endpoint: '/gradients',
    extractData: json => json.gradients || [],
});

// ── Game Integration caches ──

export let _cachedGameIntegrations: GameIntegration[] = [];
export const gameIntegrationsCache = new DataCache<GameIntegration[]>({
    endpoint: '/game-integrations',
    extractData: json => json.integrations || [],
});
gameIntegrationsCache.subscribe(v => { _cachedGameIntegrations = v; });

export let _cachedGameAdapters: GameAdapterInfo[] = [];
export const gameAdaptersCache = new DataCache<GameAdapterInfo[]>({
    endpoint: '/game-adapters',
    extractData: json => json.adapters || [],
});
gameAdaptersCache.subscribe(v => { _cachedGameAdapters = v; });

// ── Audio Processing Templates caches ──

export const audioProcessingTemplatesCache = new DataCache<any[]>({
    endpoint: '/audio-processing-templates',
    extractData: json => json.templates || [],
});
audioProcessingTemplatesCache.subscribe(v => { _cachedAudioProcessingTemplates = v; });

export const audioFilterDefsCache = new DataCache<any[]>({
    endpoint: '/audio-filters',
    extractData: json => json.filters || [],
});
audioFilterDefsCache.subscribe(v => { _cachedAudioFilterDefs = v; });
