/**
 * Servicio de autenticación con Keycloak
 */
import Keycloak from 'keycloak-js';
import { writable, derived } from 'svelte/store';
import { browser } from '$app/environment';

// Tipos
export interface User {
	id: string;
	username: string;
	email?: string;
	name?: string;
	tenantId?: number;
	roles: string[];
}

export interface AuthState {
	isAuthenticated: boolean;
	isLoading: boolean;
	user: User | null;
	token: string | null;
}

// Configuración de Keycloak
const keycloakConfig = {
	url: import.meta.env.VITE_KEYCLOAK_URL,
	realm: import.meta.env.VITE_KEYCLOAK_REALM,
	clientId: import.meta.env.VITE_KEYCLOAK_CLIENT_ID
};

// Instancia de Keycloak
let keycloakInstance: Keycloak | null = null;

// Helper para obtener cookies
const getCookie = (name: string): string | null => {
	if (!browser) return null;
	const value = `; ${document.cookie}`;
	const parts = value.split(`; ${name}=`);
	if (parts.length === 2) return parts.pop()?.split(';').shift() || null;
	return null;
};

// Helper para establecer cookies con las opciones correctas según el entorno
const setCookie = (name: string, value: string, days: number = 7) => {
	if (!browser) return;
	const expirationDate = new Date();
	expirationDate.setDate(expirationDate.getDate() + days);

	// En desarrollo (localhost), no usar Secure flag
	const isSecure = window.location.protocol === 'https:';
	const secureFlag = isSecure ? '; Secure' : '';

	const cookieString = `${name}=${value}; path=/; expires=${expirationDate.toUTCString()}; SameSite=Lax${secureFlag}`;
	document.cookie = cookieString;

	// Verificar que se estableció
	const verification = getCookie(name);
};

// Helper para eliminar cookies
const deleteCookie = (name: string) => {
	if (!browser) return;
	const isSecure = window.location.protocol === 'https:';
	const secureFlag = isSecure ? '; Secure' : '';
	document.cookie = `${name}=; path=/; expires=Thu, 01 Jan 1970 00:00:00 UTC; SameSite=Lax${secureFlag}`;
};

// Store de autenticación
const createAuthStore = () => {
	const { subscribe, set, update } = writable<AuthState>({
		isAuthenticated: false,
		isLoading: true,
		user: null,
		token: null
	});

	return {
		subscribe,
		setAuthenticated: (authenticated: boolean) =>
			update((state) => ({ ...state, isAuthenticated: authenticated })),
		setLoading: (loading: boolean) =>
			update((state) => ({ ...state, isLoading: loading })),
		setUser: (user: User | null) => update((state) => ({ ...state, user })),
		setToken: (token: string | null) => update((state) => ({ ...state, token })),
		setTokens: (accessToken: string, refreshToken?: string) => {
			update((state) => ({ ...state, token: accessToken }));
			if (browser && refreshToken) {
				localStorage.setItem('refresh_token', refreshToken);
			}
		},
		reset: () =>
			set({
				isAuthenticated: false,
				isLoading: false,
				user: null,
				token: null
			})
	};
};

export const authStore = createAuthStore();

// Derived store para verificar si está autenticado
export const isAuthenticated = derived(authStore, ($auth) => $auth.isAuthenticated);

// Derived store para obtener el usuario
export const currentUser = derived(authStore, ($auth) => $auth.user);

/**
 * Inicializa la autenticación (Keycloak o token-based)
 */
export const initAuth = async (): Promise<boolean> => {
	if (!browser) return false;

	try {
		authStore.setLoading(true);

		// Primero intentar restaurar sesión desde localStorage
		const token = localStorage.getItem('access_token');
		if (token) {
			authStore.setToken(token);
			authStore.setAuthenticated(true);

			// Sincronizar con cookies si no existe
			const cookieToken = getCookie('access_token');
			if (!cookieToken) {
				setCookie('access_token', token);
			}

			await loadUserInfo(token);
			authStore.setLoading(false);
			return true;
		}

		// Si no hay token local, intentar con Keycloak
		await initKeycloak();

		authStore.setLoading(false);
		return false;
	} catch (error) {
		console.error('Error inicializando autenticación:', error);
		authStore.setLoading(false);
		return false;
	}
};

/**
 * Inicializa Keycloak
 */
export const initKeycloak = async (): Promise<boolean> => {
	if (!browser) return false;

	try {
		keycloakInstance = new Keycloak(keycloakConfig);

		const authenticated = await keycloakInstance.init({
			onLoad: 'check-sso',
			silentCheckSsoRedirectUri: window.location.origin + '/silent-check-sso.html',
			pkceMethod: 'S256',
			checkLoginIframe: false
		});

		if (authenticated) {
			await updateAuthState();
			setupTokenRefresh();
		}

		return authenticated;
	} catch (error) {
		console.error('Error inicializando Keycloak:', error);
		return false;
	}
};

// Variable para rastrear el tenant anterior
let previousTenantId: number | undefined = undefined;

/**
 * Actualiza el estado de autenticación con los datos de Keycloak
 */
const updateAuthState = async () => {
	if (!keycloakInstance?.authenticated) {
		authStore.reset();
		return;
	}

	try {
		const profile = await keycloakInstance.loadUserProfile();
		const token = keycloakInstance.token || null;
		const tokenParsed = keycloakInstance.tokenParsed as any;

		const roles = tokenParsed?.realm_access?.roles || [];
		const tenantId = tokenParsed?.tenant_id || tokenParsed?.attributes?.tenant_id;
		const newTenantId = tenantId ? parseInt(tenantId) : undefined;

		// Detectar si cambió el tenant
		const tenantChanged = previousTenantId !== undefined && previousTenantId !== newTenantId;

		const user: User = {
			id: profile.id || '',
			username: profile.username || '',
			email: profile.email,
			name: `${profile.firstName || ''} ${profile.lastName || ''}`.trim(),
			tenantId: newTenantId,
			roles
		};

		authStore.setAuthenticated(true);
		authStore.setUser(user);
		authStore.setToken(token);

		// Si cambió el tenant, limpiar el store de compañías
		if (tenantChanged && browser) {
			try {
				const { companyStore } = await import('./stores/company.svelte');
				companyStore.clear();
			} catch (error) {
				console.error('Error al limpiar store de compañías:', error);
			}
		}

		// Actualizar el tenant anterior
		previousTenantId = newTenantId;
	} catch (error) {
		console.error('Error actualizando estado de autenticación:', error);
		authStore.reset();
	}
};

/**
 * Configura el refresh automático del token
 */
const setupTokenRefresh = () => {
	if (!keycloakInstance) return;

	// Refrescar token cada 60 segundos si está cerca de expirar
	keycloakInstance.onTokenExpired = () => {
		keycloakInstance
			?.updateToken(70)
			.then((refreshed) => {
				if (refreshed) {
					authStore.setToken(keycloakInstance?.token || null);
				}
			})
			.catch(() => {
				console.error('Error refrescando token');
				logout();
			});
	};
};

/**
 * Inicia sesión con Keycloak (OAuth flow)
 */
export const loginWithKeycloak = async (tenantSlug?: string) => {
	if (!keycloakInstance) {
		console.error('Keycloak no está inicializado');
		return;
	}

	const options: any = {
		redirectUri: window.location.origin + '/callback'
	};

	if (tenantSlug) {
		options.loginHint = tenantSlug;
	}

	await keycloakInstance.login(options);
};

/**
 * Inicia sesión con credenciales (username/password)
 * Nota: Esta función ya no se usa directamente desde el login form,
 * el login ahora se hace mediante form actions del servidor.
 * Se mantiene para compatibilidad con SSO y otros flujos.
 */
export const login = async (credentials: {
	username: string;
	password: string;
	tenant_slug: string;
}): Promise<{ success: boolean; error?: string; data?: any }> => {
	try {
		// Usar la API centralizada
		const { api } = await import('./api');
		const response = await api.auth.login(credentials);

		// Si hay error en la respuesta
		if (response.error) {
			return {
				success: false,
				error: response.error
			};
		}

		// Guardar tokens y actualizar estado
		const loginData = response.data;
		if (loginData?.access_token) {
			authStore.setToken(loginData.access_token);
			authStore.setAuthenticated(true);

			// Guardar también en localStorage para persistencia
			if (browser) {
				localStorage.setItem('access_token', loginData.access_token);
				if (loginData.refresh_token) {
					localStorage.setItem('refresh_token', loginData.refresh_token);
				}

				// Guardar en cookies para que el servidor pueda acceder
				setCookie('access_token', loginData.access_token);
				if (loginData.refresh_token) {
					setCookie('refresh_token', loginData.refresh_token);
				}
			}

			// Cargar información del usuario
			await loadUserInfo(loginData.access_token);
		}

		return {
			success: true,
			data: loginData
		};
	} catch (error) {
		console.error('Error en login:', error);
		return {
			success: false,
			error: 'Error de conexión con el servidor'
		};
	}
};

/**
 * Carga la información del usuario desde el token
 */
const loadUserInfo = async (token: string) => {
	try {
		// Guardar temporalmente el token para que api.ts lo use
		authStore.setToken(token);

		// Usar la API centralizada
		const { api } = await import('./api');
		const response = await api.auth.me();

		if (response.data) {
			const data = response.data;
			const user: User = {
				id: data.sub || '',
				username: data.preferred_username || data.username || '',
				email: data.email,
				name: data.name,
				tenantId: data.tenant_id,
				roles: data.realm_access?.roles || []
			};
			authStore.setUser(user);
		}
	} catch (error) {
		console.error('Error cargando información del usuario:', error);
	}
};

/**
 * Cierra sesión
 */
export const logout = async () => {
	if (!browser) return;

	try {
		// Capturar tokens antes de limpiar nada
		const refreshToken = localStorage.getItem('refresh_token');
		const accessToken = localStorage.getItem('access_token');

		// Limpiar store de compañías
		try {
			const { companyStore } = await import('./stores/company.svelte');
			companyStore.clear();
		} catch (error) {
			console.error('Error al limpiar store de compañías:', error);
		}

		// Limpiar estado local
		authStore.reset();
		localStorage.removeItem('access_token');
		localStorage.removeItem('refresh_token');
		deleteCookie('access_token');
		deleteCookie('refresh_token');

		// Si hay instancia de Keycloak, hacer logout de Keycloak
		if (keycloakInstance?.authenticated) {
			// Primero notificamos al servidor para limpieza de cookies (SvelteKit)
			try {
				await fetch('/logout', {
					method: 'POST'
				});
			} catch (e) {
				console.error("Error calling server logout:", e);
			}

			await keycloakInstance.logout({
				redirectUri: window.location.origin + '/login'
			});
			return;
		}

		// Llamar al endpoint del servidor para limpiar cookies de SvelteKit
		// Usar un formulario para hacer POST y permitir la redirección
		const form = document.createElement('form');
		form.method = 'POST';
		form.action = '/logout';



		document.body.appendChild(form);
		form.submit();

	} catch (error) {
		console.error('Error durante logout:', error);
		// Asegurar que se redirija al login aunque haya error
		window.location.href = '/login';
	}
};

/**
 * Verifica si el usuario tiene un rol específico
 */
export const hasRole = (role: string): boolean => {
	if (!keycloakInstance?.authenticated) return false;
	return keycloakInstance.hasRealmRole(role);
};

/**
 * Obtiene el token de acceso actual
 */
export const getToken = (): string | null => {
	// Intentar obtener de Keycloak primero
	if (keycloakInstance?.token) {
		return keycloakInstance.token;
	}

	// Si no, intentar de localStorage
	if (browser) {
		let token = localStorage.getItem('access_token');

		// Si no hay token en localStorage, intentar de las cookies
		if (!token) {
			token = getCookie('access_token');
			// Si lo encontramos en cookies, sincronizarlo a localStorage
			if (token) {
				localStorage.setItem('access_token', token);
			}
		}

		return token;
	}

	return null;
};

/**
 * Refresca el access token usando el refresh token
 */
export const refreshAccessToken = async (): Promise<boolean> => {
	if (!browser) return false;

	const refreshToken = localStorage.getItem('refresh_token');
	if (!refreshToken) {
		return false;
	}

	try {
		const { api } = await import('./api');
		const response = await api.auth.refresh(refreshToken);

		if (response.error || !response.data) {
			console.error('Failed to refresh token:', response.error);
			// Si falla el refresh, hacer logout
			await logout();
			return false;
		}

		// Actualizar tokens
		const newAccessToken = response.data.access_token;
		const newRefreshToken = response.data.refresh_token;

		authStore.setToken(newAccessToken);
		localStorage.setItem('access_token', newAccessToken);

		if (newRefreshToken) {
			localStorage.setItem('refresh_token', newRefreshToken);
		}

		// Actualizar también la cookie
		setCookie('access_token', newAccessToken);
		return true;

	} catch (error) {
		await logout();
		return false;
	}
};

/**
 * Obtiene el refresh token
 */
export const getRefreshToken = (): string | null => {
	if (!browser) return null;
	return localStorage.getItem('refresh_token');
};

/**
 * Obtiene la instancia de Keycloak
 */
export const getKeycloakInstance = (): Keycloak | null => {
	return keycloakInstance;
};
