/**
 * Store para manejar la compañía activa del usuario
 * Permite cambiar entre las compañías que pertenecen al tenant
 */

import { browser } from '$app/environment';

interface Company {
	id: number;
	name: string;
	rfc?: string;
	logo?: string;
	tenant_id: number;
	tenant_name?: string;
	tenant_slug?: string;
}

class CompanyStore {
	private _activeCompany = $state<Company | null>(null);
	private _companies = $state<Company[]>([]);
	private _loading = $state(false);
	private _currentTenantId = $state<number | null>(null);

	get activeCompany() {
		return this._activeCompany;
	}

	get companies() {
		return this._companies;
	}

	get loading() {
		return this._loading;
	}

	/**
	 * Carga las compañías del tenant del usuario desde el backend
	 * @param preloadedCompanies - Compañías pre-cargadas desde el servidor (SSR)
	 */
	async loadCompanies(preloadedCompanies?: Company[], activeCompanyId?: number) {
		// Si tenemos compañías pre-cargadas, usarlas directamente
		if (preloadedCompanies && preloadedCompanies.length > 0) {
			// Detectar si el tenant ha cambiado
			const newTenantId = preloadedCompanies[0].tenant_id;

			// Si el tenant cambió, limpiar el store primero
			if (this._currentTenantId !== null && this._currentTenantId !== newTenantId) {
				this.clear();
			}

			this._currentTenantId = newTenantId;
			this._companies = preloadedCompanies;

			// Si hay compañías y no hay una activa, seleccionar la correcta.
			// IMPORTANTE: `setActiveCompany` es async (dispara syncCompanyPermissions);
			// hay que `await` para que el caller (initialize → markPermissionsHydrated)
			// no marque la hidratación antes de que los permisos del backend lleguen.
			if (this._companies.length > 0 && !this._activeCompany) {
				// Prioridad 1: ID pasado por parámetro (desde SSR/Cookie)
				if (activeCompanyId) {
					const company = this._companies.find(c => c.id === activeCompanyId);
					if (company) {
						await this.setActiveCompany(company, true);
						return;
					}
				}

				// Prioridad 2: Intentar restaurar de localStorage (Browser only)
				if (typeof window !== 'undefined') {
					const savedId = localStorage.getItem('activeCompanyId');
					if (savedId) {
						const company = this._companies.find(c => c.id === parseInt(savedId));
						if (company) {
							await this.setActiveCompany(company, true); // silent=true para inicialización
							return;
						}
					}
				}
				// Prioridad 3: Si no hay nada, seleccionar la primera
				await this.setActiveCompany(this._companies[0], true); // silent=true para inicialización
			}
			return;
		}

		// Si no hay datos pre-cargados, hacer fetch (fallback)
		// Solo en el navegador, nunca durante SSR
		if (!browser) {
			return;
		}

		this._loading = true;
		try {
			// Importamos dinámicamente para evitar dependencias circulares si las hubiera
			const { api } = await import('$lib/api');
			const response = await api.get<Company[]>('/v1/auth/my-companies');

			if (response.data) {
				const newCompanies = response.data;

				// Detectar si el tenant ha cambiado
				if (newCompanies.length > 0) {
					const newTenantId = newCompanies[0].tenant_id;

					// Si el tenant cambió, limpiar el store primero
					if (this._currentTenantId !== null && this._currentTenantId !== newTenantId) {
						this.clear();
					}

					this._currentTenantId = newTenantId;
				}

				this._companies = newCompanies;

				// Si hay compañías y no hay una activa, seleccionar la primera.
				// `await` necesario para esperar a syncCompanyPermissions antes de
				// que la inicialización del layout marque permissionsHydrated.
				if (this._companies.length > 0 && !this._activeCompany) {
					await this.setActiveCompany(this._companies[0], true); // silent=true para inicialización
				}
			} else {
				console.error('Error loading companies:', response.error);
				if (response.status === 402) {
					const { toast } = await import('svelte-sonner');
					toast.error('Licencia inactiva', {
						duration: 8000,
						description: response.error || 'Tu licencia no está activa para este tenant. Contacta al administrador.'
					});
					this.clear();
				} else if (response.status === 401) {
					this.clear();
				}
			}
		} catch (error) {
			console.error('Error loading companies:', error);
		} finally {
			this._loading = false;
		}
	}

	/**
	 * Establece la compañía activa
	 * @param company - La compañía a establecer como activa
	 * @param silent - Si es true, no dispara el evento companyChanged (para inicialización)
	 */
	async setActiveCompany(company: Company, silent: boolean = false) {
		const previousCompanyId = this._activeCompany?.id;
		this._activeCompany = company;

		// Guardar en localStorage para persistencia
		if (typeof window !== 'undefined') {
			localStorage.setItem('activeCompanyId', company.id.toString());
		}

		// Guardar en cookie para acceso desde el servidor (SSR)
		// Usar el endpoint del servidor para garantizar que la cookie esté disponible en SSR
		if (browser) {
			try {
				await fetch('/api-sveltekit/company/set-active', {
					method: 'POST',
					headers: {
						'Content-Type': 'application/json'
					},
					// tenant_id de la compañía → override para que el backend escale por
					// ese tenant (necesario cuando el usuario es hub_admin sin tenant en el token).
					body: JSON.stringify({ companyId: company.id, tenantId: company.tenant_id }),
					credentials: 'include'
				});
			} catch (error) {
				console.error('Error setting active company cookie:', error);
			}
			try {
				const { syncCompanyPermissions } = await import('$lib/auth');
				await syncCompanyPermissions(company.id);
			} catch (e) {
				console.warn('syncCompanyPermissions:', e);
			}
		}

		// Despachar evento personalizado solo si:
		// 1. No es silent (no es inicialización)
		// 2. Y realmente cambió la compañía (el ID es diferente)
		if (!silent && typeof window !== 'undefined' && previousCompanyId !== company.id) {
			window.dispatchEvent(new CustomEvent('companyChanged', {
				detail: { companyId: company.id }
			}));
		}
	}

	/**
	 * Actualiza los datos de une empresa en el store localmente
	 * Útil para reflejar cambios inmediatos (ej: cambio de logo) sin recargar
	 */
	updateCompany(id: number, data: Partial<Company>) {
		// 1. Actualizar en la lista
		const index = this._companies.findIndex(c => c.id === id);
		if (index !== -1) {
			this._companies[index] = { ...this._companies[index], ...data };

			// 2. Si es la activa, actualizar también
			if (this._activeCompany?.id === id) {
				this._activeCompany = { ...this._activeCompany, ...data };
				// Actualizar persistencia si es necesario
				if (typeof window !== 'undefined') {
					// Disparar evento para notificar cambios a componentes que no usan el store reactivo directo (si los hay)
					window.dispatchEvent(new CustomEvent('companyChanged', {
						detail: { companyId: id }
					}));
				}
			}
		}
	}

	/**
	 * Restaura la compañía activa desde localStorage
	 */
	restoreActiveCompany() {
		if (typeof window !== 'undefined') {
			const savedId = localStorage.getItem('activeCompanyId');
			if (savedId && this._companies.length > 0) {
				const company = this._companies.find(c => c.id === parseInt(savedId));
				if (company) {
					this._activeCompany = company;
				}
			}
		}
	}

	/**
	 * Limpia el store (útil al cambiar de tenant o cerrar sesión)
	 */
	clear() {
		this._activeCompany = null;
		this._companies = [];
		this._loading = false;
		this._currentTenantId = null;

		// Limpiar localStorage
		if (typeof window !== 'undefined') {
			localStorage.removeItem('activeCompanyId');
		}

		// Limpiar cookie
		if (typeof document !== 'undefined') {
			document.cookie = 'active_company_id=; path=/; max-age=0';
		}
	}

	/**
	 * Inicializa el store cargando las compañías
	 * @param preloadedCompanies - Compañías pre-cargadas desde el servidor (SSR)
	 */
	async initialize(preloadedCompanies?: Company[], activeCompanyId?: number) {
		await this.loadCompanies(preloadedCompanies, activeCompanyId);
		// Si no hay compañías pre-cargadas, intentar restaurar de localStorage
		if (!preloadedCompanies) {
			this.restoreActiveCompany();
		}
	}
}

export const companyStore = new CompanyStore();
