import { env } from '$env/dynamic/private';
import { redirect, type Cookies } from '@sveltejs/kit';

const DEFAULT_WORKSPACE_BASE_URL = 'https://workspace.aduanasoft.com';
const RETURN_PATH_COOKIE = 'workspace_return_path';

/**
 * Returns true only when the public-facing URL uses HTTPS.
 * Use this for cookie `secure` flag instead of NODE_ENV so that
 * cookies work on HTTP LAN dev environments (e.g. 192.168.x.x).
 */
export function isSecureContext(): boolean {
	const origin = (env.ORIGIN || process.env.ORIGIN || '').trim();
	if (origin) return origin.startsWith('https://');
	return process.env.NODE_ENV === 'production';
}

function stripTrailingSlashes(value: string): string {
	return value.replace(/\/+$/, '');
}

/**
 * Detecta si una URL apunta a un host que solo es accesible localmente:
 * localhost, 127.0.0.1, IPs de red LAN/privada y hostnames internos de Docker.
 * Estas URLs no son válidas como redirect_uri ni como KC public URL en producción.
 */
function isDevOnlyUrl(rawUrl: string): boolean {
	try {
		const parsed = new URL(rawUrl);
		const host = parsed.hostname.toLowerCase();
		return (
			host === 'localhost' ||
			host === '127.0.0.1' ||
			host === 'host.docker.internal' ||
			host === 'backend' ||
			host === 'hub-keycloak' ||
			/^192\.168\./.test(host) ||
			/^10\./.test(host) ||
			/^172\.(1[6-9]|2\d|3[01])\./.test(host)
		);
	} catch {
		return false;
	}
}

export function getWorkspaceBaseUrl(): string {
	const candidates = [
		(env.VITE_HUB_URL || '').trim(),
		(env.HUB_URL || '').trim(),
		DEFAULT_WORKSPACE_BASE_URL
	].filter(Boolean);

	for (const candidate of candidates) {
		if (!isDevOnlyUrl(candidate)) {
			return stripTrailingSlashes(candidate);
		}
	}

	return DEFAULT_WORKSPACE_BASE_URL;
}

/**
 * Normaliza la URL base del sistema (Anexo76) para construir redirect_uri seguros.
 *
 * Problema habitual en producción: SvelteKit deriva `url.origin` de la variable de entorno
 * `ORIGIN`. Si el contenedor se despliega con `ORIGIN=http://localhost:5173` (valor del .env
 * de dev), todos los redirect_uri generados por el servidor apuntan a localhost.
 *
 * Esta función:
 * 1. Usa `requestOrigin` si ya es una URL pública (no dev-only).
 * 2. Si es localhost, busca `SITE_URL` (env var de producción recomendada) como fallback.
 * 3. Como último recurso devuelve requestOrigin tal cual (entorno dev genuino).
 *
 * Var de entorno recomendada en producción:
 *   SITE_URL=https://anexo76-dev.aduanasoft.com   (además de arreglar ORIGIN)
 */
export function resolveSystemBaseUrl(requestOrigin: string): string {
	if (!isDevOnlyUrl(requestOrigin)) {
		return stripTrailingSlashes(requestOrigin);
	}

	// requestOrigin es dev-only → ORIGIN env var apunta a localhost en producción.
	// Buscar URL pública en env vars adicionales.
	const candidates = [
		(env.SITE_URL || '').trim(),
		(env.APP_URL || '').trim(),
		(env.PUBLIC_URL || '').trim(),
	];

	for (const candidate of candidates) {
		if (candidate && !isDevOnlyUrl(candidate)) {
			return stripTrailingSlashes(candidate);
		}
	}

	// Entorno dev genuino: devolver requestOrigin tal cual
	return stripTrailingSlashes(requestOrigin);
}

export type WorkspaceLoginUrlOptions = {
	/**
	 * URL del login del Hub sin `return_to`. Usar en `post_logout_redirect_uri` para que,
	 * tras logout en KC, el Hub aplique myApps() (launcher si el usuario tiene varias apps).
	 * Con `return_to` a Anexo76, el re-login siempre rebotaba a esa app aunque hubiera más.
	 */
	forPostLogout?: boolean;
};

export function getWorkspaceLoginUrl(
	systemBaseUrl: string,
	options?: WorkspaceLoginUrlOptions
): string {
	const workspaceBaseUrl = getWorkspaceBaseUrl();
	if (options?.forPostLogout) {
		return `${workspaceBaseUrl}/login`;
	}
	// return_to includes sso_verified=1 so the workspace preserves it when redirecting
	// back, regardless of what additional params the workspace appends.
	const loginUrl = `${systemBaseUrl}/login?sso_verified=1`;
	return `${workspaceBaseUrl}/login?return_to=${encodeURIComponent(loginUrl)}`;
}

export function storeReturnPath(cookies: Cookies, path: string): void {
	if (!path || !path.startsWith('/')) return;
	cookies.set(RETURN_PATH_COOKIE, path, {
		path: '/',
		httpOnly: true,
		sameSite: 'lax',
		secure: isSecureContext(),
		maxAge: 60 * 10
	});
}

export function getPublicKeycloakBaseUrl(): string {
	const configuredKeycloakUrl = (env.VITE_KEYCLOAK_URL || '').trim();
	// Si VITE_KEYCLOAK_URL apunta a un host dev-only (localhost, IP LAN, Docker service),
	// ignorarlo y derivar la URL del hostname público del Workspace.
	// Esto protege contra builds donde el .env de dev llega a producción por error.
	if (configuredKeycloakUrl && !isDevOnlyUrl(configuredKeycloakUrl)) {
		return stripTrailingSlashes(configuredKeycloakUrl);
	}

	return `${getWorkspaceBaseUrl()}/kcauth`;
}

export function getKeycloakRealm(): string {
	return (env.KEYCLOAK_REALM || env.VITE_KEYCLOAK_REALM || 'master').trim();
}

export function getKeycloakClientId(): string {
	return (env.KEYCLOAK_CLIENT_ID || env.VITE_KEYCLOAK_CLIENT_ID || 'anexo76-frontend').trim();
}

export function getCleanReturnPath(url: URL): string {
	const cleanParams = new URLSearchParams(url.searchParams);
	cleanParams.delete('sso_verified');

	const queryString = cleanParams.toString();
	return queryString ? `${url.pathname}?${queryString}` : url.pathname;
}

export function storeWorkspaceReturnPath(cookies: Cookies, url: URL): string {
	const returnPath = getCleanReturnPath(url);

	cookies.set(RETURN_PATH_COOKIE, returnPath, {
		path: '/',
		httpOnly: true,
		sameSite: 'lax',
		secure: isSecureContext(),
		maxAge: 60 * 10
	});

	return returnPath;
}

export function readWorkspaceReturnPath(cookies: Cookies, fallbackPath: string): string {
	const storedReturnPath = cookies.get(RETURN_PATH_COOKIE);
	if (storedReturnPath && storedReturnPath.startsWith('/')) {
		return storedReturnPath;
	}

	return fallbackPath;
}

export function clearWorkspaceReturnPath(cookies: Cookies): void {
	cookies.delete(RETURN_PATH_COOKIE, { path: '/' });
}

export function buildKeycloakAuthorizationUrl(systemBaseUrl: string, redirectPath: string): string {
	const keycloakBaseUrl = getPublicKeycloakBaseUrl();
	// resolveSystemBaseUrl corrige el caso donde url.origin es localhost por ORIGIN env var mal configurado
	const publicBase = resolveSystemBaseUrl(systemBaseUrl);
	const redirectUri = `${publicBase}/auth/callback`;
	const state = JSON.stringify({ redirect_url: redirectPath });
	const params = new URLSearchParams({
		client_id: getKeycloakClientId(),
		redirect_uri: redirectUri,
		response_type: 'code',
		scope: 'openid',
		prompt: 'none',
		state
	});

	return `${keycloakBaseUrl}/realms/${getKeycloakRealm()}/protocol/openid-connect/auth?${params.toString()}`;
}

/**
 * Construye URL de login directo en KC sin prompt=none.
 * Usa la sesión KC existente si la hay; si no, muestra el form de login.
 * Usar cuando se recibe ?redirect= del Hub (rompe el loop Hub↔login).
 */
export function buildKeycloakLoginUrl(systemBaseUrl: string, redirectPath: string): string {
	const keycloakBaseUrl = getPublicKeycloakBaseUrl();
	// resolveSystemBaseUrl corrige el caso donde url.origin es localhost por ORIGIN env var mal configurado
	const publicBase = resolveSystemBaseUrl(systemBaseUrl);
	const redirectUri = `${publicBase}/auth/callback`;
	const state = JSON.stringify({ redirect_url: redirectPath });
	const params = new URLSearchParams({
		client_id: getKeycloakClientId(),
		redirect_uri: redirectUri,
		response_type: 'code',
		scope: 'openid',
		state
	});

	return `${keycloakBaseUrl}/realms/${getKeycloakRealm()}/protocol/openid-connect/auth?${params.toString()}`;
}

export function redirectToWorkspaceLogin(cookies: Cookies, url: URL): never {
	storeWorkspaceReturnPath(cookies, url);
	throw redirect(303, getWorkspaceLoginUrl(url.origin));
}

export function redirectToKeycloakAuthorization(systemBaseUrl: string, redirectPath: string): never {
	throw redirect(303, buildKeycloakAuthorizationUrl(systemBaseUrl, redirectPath));
}

export function redirectToKeycloakLogin(systemBaseUrl: string, redirectPath: string): never {
	throw redirect(303, buildKeycloakLoginUrl(systemBaseUrl, redirectPath));
}

export function buildKeycloakLogoutUrl(systemBaseUrl: string, idTokenHint?: string): string {
	const keycloakBaseUrl = getPublicKeycloakBaseUrl();
	const postLogoutRedirectUri = `${systemBaseUrl}/auth/post-logout`;
	const params = new URLSearchParams({
		client_id: getKeycloakClientId(),
		post_logout_redirect_uri: postLogoutRedirectUri
	});

	// Con id_token_hint KC acepta cualquier post_logout_redirect_uri sin necesidad
	// de que esté registrado explícitamente en el cliente.
	if (idTokenHint) {
		params.set('id_token_hint', idTokenHint);
	}

	return `${keycloakBaseUrl}/realms/${getKeycloakRealm()}/protocol/openid-connect/logout?${params.toString()}`;
}