import { redirect, type Cookies } from '@sveltejs/kit';
import type { SystemType } from '$lib/stores/system.svelte';
import { authenticatedFetch } from '$lib/server/api';
import { getWorkspaceBaseUrl } from '$lib/server/workspace-auth';

const VALID_SYSTEMS = new Set<SystemType>(['fixed_asset', 'inventory']);

export function isValidSystem(value: string | null | undefined): value is SystemType {
	return typeof value === 'string' && VALID_SYSTEMS.has(value as SystemType);
}

function parseSystemsArray(raw: unknown): SystemType[] {
	if (!Array.isArray(raw)) return [];
	return raw.filter((s): s is SystemType => typeof s === 'string' && isValidSystem(s));
}

/** Decodifica el payload del JWT (sin verificar firma; el token ya fue validado vía Hub). */
export function decodeJwtPayload(token: string): Record<string, unknown> | null {
	try {
		const parts = token.split('.');
		if (parts.length < 2) return null;
		const payload = parts[1].replace(/-/g, '+').replace(/_/g, '/');
		const padded = payload + '='.repeat((4 - (payload.length % 4)) % 4);
		const json = Buffer.from(padded, 'base64').toString('utf8');
		return JSON.parse(json) as Record<string, unknown>;
	} catch {
		return null;
	}
}

/** Combina claims del JWT con la respuesta de /auth/me (Hub). */
export function mergeTokenClaims(
	userData: Record<string, unknown> | null | undefined,
	accessToken: string
): Record<string, unknown> {
	const jwtClaims = decodeJwtPayload(accessToken) ?? {};
	return { ...jwtClaims, ...(userData ?? {}) };
}

/**
 * Sistemas permitidos según el token (claim `allowed_systems`).
 * El Hub/Keycloak lo incluye cuando el usuario entra desde Workspace.
 */
export function extractAllowedSystemsFromToken(
	tokenClaims: Record<string, unknown> | null | undefined
): SystemType[] {
	if (!tokenClaims) return [];
	return parseSystemsArray(tokenClaims.allowed_systems ?? tokenClaims.allowedSystems);
}

export function setActiveSystemCookie(cookies: Cookies, system: SystemType) {
	cookies.set('active_system', system, {
		path: '/',
		maxAge: 60 * 60 * 24 * 30, // 30 días
		sameSite: 'lax',
		httpOnly: false,
		secure: process.env.NODE_ENV === 'production'
	});
}

export function resolveActiveCompanyId<T extends { id: number }>(
	cookies: Cookies,
	companies: T[]
): number | null {
	const cookieCompanyId = cookies.get('active_company_id');
	if (cookieCompanyId) {
		const cookieId = Number.parseInt(cookieCompanyId, 10);
		if (Number.isFinite(cookieId) && companies.some((c) => c.id === cookieId)) return cookieId;
	}
	return companies.length > 0 ? companies[0].id : null;
}

/** Permisos RBAC por compañía (fallback / validación en set-active). */
export async function fetchAllowedSystems(
	cookies: Cookies,
	fetch: typeof globalThis.fetch,
	companyId: number
): Promise<SystemType[]> {
	const res = await authenticatedFetch(
		`v1/core/permissions/me?company_id=${companyId}`,
		{ method: 'GET' },
		cookies,
		fetch
	);
	if (!res.ok) return [];
	const data = (await res.json()) as { allowed_systems?: unknown };
	return parseSystemsArray(data.allowed_systems);
}

export type SystemGateResult =
	| { action: 'redirect_workspace' }
	| { action: 'proceed'; activeSystem: SystemType };

/**
 * Gate obligatorio. Prioridad:
 * 1. requestedSystem del URL (Hub tiene autoridad — viene del relay firmado one-time)
 * 2. cookieSystem validado contra allowedSystems del JWT
 * 3. Primer sistema de allowedSystems del JWT
 * 4. redirect_workspace si nada resuelve
 *
 * requestedSystem se acepta incluso si el JWT no trae allowed_systems (Keycloak sin claim):
 * el backend valida RBAC en cada request de API.
 */
export function resolveSystemGate(params: {
	tokenClaims: Record<string, unknown> | null | undefined;
	cookieSystem?: string | null;
	requestedSystem?: string | null;
}): SystemGateResult {
	const requestedSystem = params.requestedSystem;
	if (isValidSystem(requestedSystem)) {
		return { action: 'proceed', activeSystem: requestedSystem };
	}

	const allowedSystems = extractAllowedSystemsFromToken(params.tokenClaims);

	const cookieSystem = params.cookieSystem;
	if (isValidSystem(cookieSystem)) {
		return { action: 'proceed', activeSystem: cookieSystem };
	}

	if (allowedSystems.length > 0) {
		return { action: 'proceed', activeSystem: allowedSystems[0] };
	}

	return { action: 'redirect_workspace' };
}

export function redirectToWorkspaceBase(): never {
	throw redirect(303, getWorkspaceBaseUrl());
}
