/**
 * Store reactivo de catálogos de referencia del CRM.
 *
 * Carga desde el backend (/v1/crm/catalogs) y cachea por catálogo. Los
 * formularios leen `options(catalog)` (reactivo) sin refetch. Los catálogos
 * dependientes (Estado por País) se piden con `ensure(catalog, parentCode)`.
 */
import { referenceCatalogsAPI } from '$lib/api/crm/catalogs';
import { companyStore } from '$lib/stores/company.svelte';
import type { Option } from '$lib/components/crm/format';

class CrmCatalogStore {
	private _cache = $state<Record<string, Option[]>>({});
	private _pending = new Set<string>();
	private _companyId: number | null = null;

	/** Toma la compañía activa; si cambió, limpia el caché. Devuelve su id (o null). */
	private syncCompany(): number | null {
		const cid = companyStore.activeCompany?.id ?? null;
		if (cid !== this._companyId) {
			this._companyId = cid;
			this._cache = {};
			this._pending.clear();
		}
		return cid;
	}

	private keyOf(catalog: string, parentCode?: string): string {
		return parentCode ? `${catalog}:${parentCode}` : catalog;
	}

	/** Opciones de un catálogo ya cargado (vacío si aún no se ha cargado). */
	options(catalog: string, parentCode?: string): Option[] {
		return this._cache[this.keyOf(catalog, parentCode)] ?? [];
	}

	/** Descripción de una clave (para listados/detalle). */
	label(catalog: string, code: string | null | undefined): string {
		if (!code) return '—';
		return this.options(catalog).find((o) => o.value === code)?.label ?? code;
	}

	/** Carga un catálogo (con dependiente opcional) si aún no está en caché. */
	async ensure(catalog: string, parentCode?: string): Promise<void> {
		const cid = this.syncCompany();
		const key = this.keyOf(catalog, parentCode);
		if (cid == null || key in this._cache || this._pending.has(key)) return;
		this._pending.add(key);
		try {
			const items = await referenceCatalogsAPI.list(catalog, cid, parentCode);
			this._cache[key] = items.map((i) => ({ value: i.code, label: i.label }));
		} catch {
			this._cache[key] = [];
		} finally {
			this._pending.delete(key);
		}
	}

	/** Precarga varios catálogos globales en paralelo. */
	async preload(catalogs: string[]): Promise<void> {
		await Promise.all(catalogs.map((c) => this.ensure(c)));
	}

	/** Invalida el caché de un catálogo (tras editar en administración). */
	invalidate(catalog?: string): void {
		if (!catalog) {
			this._cache = {};
			return;
		}
		for (const k of Object.keys(this._cache)) {
			if (k === catalog || k.startsWith(`${catalog}:`)) delete this._cache[k];
		}
		this._cache = { ...this._cache };
	}
}

export const crmCatalogs = new CrmCatalogStore();
