/**
 * Cliente API — Catálogos del SAT (solo lectura).
 *
 * Son catálogos fijos que publica el SAT: una vez cargados no cambian durante la
 * sesión, así que se guardan en un `Map` del módulo para no repetir la petición en
 * cada selector. No hay POST/PUT/PATCH/DELETE: el backend tampoco los expone.
 */
import { api } from '$lib/api';

export interface SatCatalogItem {
	id: number;
	code: string;
	description: string;
	is_active: boolean;
}

export interface SatTaxRegime extends SatCatalogItem {
	applies_to_individual: boolean; // persona física
	applies_to_legal_entity: boolean; // persona moral
}

export interface SatTax extends SatCatalogItem {
	is_withholding: boolean;
	is_transferred: boolean;
	is_local: boolean;
}

/** `description` es la nota larga del SAT y puede venir vacía; el nombre corto va en `name`. */
export interface SatUnitOfMeasure extends Omit<SatCatalogItem, 'description'> {
	description: string | null;
	name: string;
	symbol: string | null;
}

export type PersonType = 'fisica' | 'moral';

type CatalogParams = Record<string, string | number | boolean | undefined>;

/** Cache en memoria del módulo, con la query string completa como llave. */
const cache = new Map<string, unknown>();

function buildQuery(companyId: number, params?: CatalogParams): string {
	const qs = new URLSearchParams({ company_id: String(companyId) });
	for (const [key, value] of Object.entries(params ?? {})) {
		if (value !== undefined && value !== '') qs.set(key, String(value));
	}
	qs.sort(); // llave de cache estable sin importar el orden de los parámetros
	return qs.toString();
}

async function fetchCatalog<T>(
	path: string,
	companyId: number,
	params?: CatalogParams
): Promise<T[]> {
	const query = buildQuery(companyId, params);
	const key = `${path}?${query}`;
	const cached = cache.get(key);
	if (cached) return cached as T[];

	const res = await api.get<T[]>(`/v1/fin/catalogs/${path}?${query}`);
	if (res.error) throw new Error(res.error);
	const rows = res.data ?? [];
	cache.set(key, rows);
	return rows;
}

/** Vacía el cache; útil tras actualizar los catálogos con `sync_catalogs`. */
export function clearCatalogCache(): void {
	cache.clear();
}

export const satCatalogsAPI = {
	taxRegimes: (
		companyId: number,
		params?: { search?: string; person_type?: PersonType; active_only?: boolean }
	) => fetchCatalog<SatTaxRegime>('tax-regimes', companyId, params),
	taxes: (companyId: number, params?: { search?: string; active_only?: boolean }) =>
		fetchCatalog<SatTax>('taxes', companyId, params),
	paymentForms: (companyId: number, params?: { search?: string; active_only?: boolean }) =>
		fetchCatalog<SatCatalogItem>('payment-forms', companyId, params),
	unitsOfMeasure: (companyId: number, params?: { search?: string; active_only?: boolean }) =>
		fetchCatalog<SatUnitOfMeasure>('units-of-measure', companyId, params),
	productsServices: (
		companyId: number,
		params?: { search?: string; limit?: number; active_only?: boolean }
	) => fetchCatalog<SatCatalogItem>('products-services', companyId, params),
	voucherTypes: (companyId: number, params?: { search?: string; active_only?: boolean }) =>
		fetchCatalog<SatCatalogItem>('voucher-types', companyId, params),
	paymentMethods: (companyId: number, params?: { search?: string; active_only?: boolean }) =>
		fetchCatalog<SatCatalogItem>('payment-methods', companyId, params),
	taxObjects: (companyId: number, params?: { search?: string; active_only?: boolean }) =>
		fetchCatalog<SatCatalogItem>('tax-objects', companyId, params),
	cfdiUses: (companyId: number, params?: { search?: string; active_only?: boolean }) =>
		fetchCatalog<SatCatalogItem>('cfdi-uses', companyId, params)
};
