/**
 * Orquestación del Hub (Workspace) para dar de alta ORGANIZACIONES (tenants) y
 * USUARIOS (invitaciones) desde el CRM.
 *
 * Principio de seguridad: SIEMPRE se llama server-side reenviando el token del
 * usuario autenticado (Bearer). Es el Hub quien valida el permiso —
 * `hub_admin`/superadmin para tenants, `hub_admin` o `admin` del tenant para
 * invitaciones. El CRM NO guarda secretos ni hace bypass de autorización.
 *
 * Endpoints del Hub (base = getHubBackendUrl()):
 *   GET  /api/v1/hub/tenants   → lista de organizaciones (solo hub_admin)
 *   POST /api/v1/hub/tenants   → crea tenant + realm Keycloak (solo hub_admin)
 *   POST /api/v1/hub/invites   → invitación de un solo uso + email (hub_admin | admin del tenant)
 */

import { getHubBackendUrl } from '$lib/server/workspace-auth';
import { hubErrorMessage, isForbiddenStatus } from '$lib/server/workspace-provision.shared';

const HUB_API_PREFIX = '/api/v1/hub';

function hubUrl(path: string): string {
	return `${getHubBackendUrl()}${HUB_API_PREFIX}${path}`;
}

export type WorkspaceTenant = {
	id: number;
	name: string;
	slug: string;
	display_name?: string | null;
	contact_name?: string | null;
	contact_email: string;
	status: string;
	is_self_hosted: boolean;
	has_license: boolean;
	created_at: string;
};

export type WorkspaceInvite = {
	id: number;
	email: string;
	tenant_slug: string;
	role: string;
	invite_url: string;
	expires_at: string;
	created_at: string;
};

export type HubResult<T> =
	| { ok: true; data: T }
	| { ok: false; status: number; forbidden: boolean; error: string };

/** Construye el resultado de error a partir de una respuesta no-2xx del Hub. */
async function toErrorResult<T>(res: Response): Promise<HubResult<T>> {
	const body = await res.json().catch(() => null);
	return {
		ok: false,
		status: res.status,
		forbidden: isForbiddenStatus(res.status),
		error: hubErrorMessage(body, res.status)
	};
}

const jsonHeaders = (accessToken: string) => ({
	Authorization: `Bearer ${accessToken}`,
	'Content-Type': 'application/json'
});

/** Lista las organizaciones del workspace. Requiere hub_admin (403 si no). */
export async function listWorkspaceTenants(
	accessToken: string,
	fetch: typeof globalThis.fetch
): Promise<HubResult<WorkspaceTenant[]>> {
	const res = await fetch(hubUrl('/tenants'), {
		headers: { Authorization: `Bearer ${accessToken}` }
	});
	if (!res.ok) return toErrorResult<WorkspaceTenant[]>(res);
	const data = (await res.json()) as { tenants?: WorkspaceTenant[] };
	return { ok: true, data: Array.isArray(data.tenants) ? data.tenants : [] };
}

export type CreateTenantInput = {
	name: string;
	slug: string;
	contact_email: string;
	contact_name?: string;
	contact_phone?: string;
	display_name?: string;
	is_self_hosted: boolean;
	app_url?: string;
};

/** Crea una organización (tenant) y provisiona su realm en Keycloak. */
export async function createWorkspaceTenant(
	accessToken: string,
	fetch: typeof globalThis.fetch,
	input: CreateTenantInput
): Promise<HubResult<WorkspaceTenant>> {
	const res = await fetch(hubUrl('/tenants'), {
		method: 'POST',
		headers: jsonHeaders(accessToken),
		body: JSON.stringify(input)
	});
	if (!res.ok) return toErrorResult<WorkspaceTenant>(res);
	return { ok: true, data: (await res.json()) as WorkspaceTenant };
}

export type CreateInviteInput = {
	email: string;
	tenant_slug: string;
	role: string;
};

/** Genera una invitación de un solo uso para un usuario en un tenant. */
export async function createWorkspaceInvite(
	accessToken: string,
	fetch: typeof globalThis.fetch,
	input: CreateInviteInput
): Promise<HubResult<WorkspaceInvite>> {
	const res = await fetch(hubUrl('/invites'), {
		method: 'POST',
		headers: jsonHeaders(accessToken),
		body: JSON.stringify(input)
	});
	if (!res.ok) return toErrorResult<WorkspaceInvite>(res);
	return { ok: true, data: (await res.json()) as WorkspaceInvite };
}
