import { clsx, type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";

export function cn(...inputs: ClassValue[]) {
	return twMerge(clsx(inputs));
};

function isInternalDockerHost(hostname: string): boolean {
	const host = hostname.toLowerCase();
	if (!host) return false;
	if (host === 'localhost' || host === '127.0.0.1') return false;
	if (host === 'backend' || host === 'hub-backend' || host === 'host.docker.internal') return true;
	// Nombres de servicio Docker suelen no contener punto.
	return !host.includes('.');
}

function getApiPublicBaseOrigin(): string {
	const raw = (import.meta.env.VITE_API_URL || '').trim();
	if (raw) {
		try {
			const parsed = new URL(raw);
			if (isInternalDockerHost(parsed.hostname)) {
				if (typeof window !== 'undefined' && window.location?.origin) {
					return window.location.origin;
				}
				return 'http://localhost:8000';
			}
			return `${parsed.protocol}//${parsed.host}`;
		} catch {
			return raw.replace(/\/+$/, '');
		}
	}

	if (typeof window !== 'undefined' && window.location?.origin) {
		return window.location.origin;
	}

	return 'http://localhost:8000';
}

function parseAbsoluteLikeUrl(value: string): URL | null {
	const trimmed = value.trim();
	if (!trimmed) return null;

	try {
		const parsed = new URL(trimmed);
		if (parsed.protocol === 'http:' || parsed.protocol === 'https:') {
			return parsed;
		}
	} catch {
	}

	// Soporta formato host:puerto/ruta sin protocolo.
	if (/^[a-z0-9.-]+:\d+\//i.test(trimmed)) {
		try {
			return new URL(`http://${trimmed}`);
		} catch {
			return null;
		}
	}

	return null;
}

function rewriteInternalHostToPublicUrl(value: string): string {
	const parsed = parseAbsoluteLikeUrl(value);
	if (!parsed) return value;

	if (isInternalDockerHost(parsed.hostname)) {
		const publicOrigin = getApiPublicBaseOrigin();
		return `${publicOrigin}${parsed.pathname}${parsed.search}${parsed.hash}`;
	}

	return value;
}

/**
 * Convierte una ruta relativa del backend en una URL completa
 * @param path Ruta relativa (ej: "/uploads/avatars/file.png") o absoluta API (ej: "/api/v1/...")
 * @returns URL completa del backend
 */
export function getBackendAssetUrl(path: string | null | undefined): string {
	if (!path) return '';

	// Si ya es una URL completa, retornarla tal cual
	if (path.startsWith('http://') || path.startsWith('https://')) {
		return rewriteInternalHostToPublicUrl(path);
	}

	if (/^[a-z0-9.-]+:\d+\//i.test(path)) {
		return rewriteInternalHostToPublicUrl(path);
	}

	const normalized = path.startsWith('/') ? path : `/${path}`;

	// Obtener la base URL del API y limpiar el / final si existe
	let baseUrl = import.meta.env.VITE_API_URL || 'http://localhost:8000';
	baseUrl = baseUrl.replace(/\/+$/, '');

	// VITE_API_URL suele ser .../api; las rutas del backend a veces vienen como /api/v1/...
	// Evitar http://host/api/api/v1/...
	if (normalized.startsWith('/api/') && baseUrl.endsWith('/api')) {
		const origin = baseUrl.slice(0, -'/api'.length);
		return `${origin}${normalized}`;
	}

	const cleanPath = normalized.startsWith('/') ? normalized.slice(1) : normalized;
	return `${baseUrl}/${cleanPath}`;
}

export function isSafeHttpUrl(value: string | null | undefined): boolean {
	if (!value) return false;
	try {
		const url = new URL(value);
		return url.protocol === 'http:' || url.protocol === 'https:';
	} catch {
		return false;
	}
}

function getHubAssetBaseUrl(): string {
	const hubBase = (import.meta.env.VITE_HUB_URL || '').trim();
	if (!hubBase) return '';
	return hubBase.replace(/\/+$/, '');
}

function normalizeWorkspaceAvatarUrl(value: string | null | undefined): string {
	if (!value || typeof value !== 'string') return '';
	const trimmed = value.trim();
	if (!trimmed) return '';

	if (isSafeHttpUrl(trimmed)) {
		return rewriteInternalHostToPublicUrl(trimmed);
	}

	if (/^[a-z0-9.-]+:\d+\//i.test(trimmed)) {
		return rewriteInternalHostToPublicUrl(trimmed);
	}

	// Workspace puede devolver rutas relativas (ej: /media/avatar.png).
	if (trimmed.startsWith('/')) {
		const hubBase = getHubAssetBaseUrl();
		if (hubBase) {
			return `${hubBase}${trimmed}`;
		}
		// Si no hay HUB_URL pública, intentar resolver en el mismo origen.
		return trimmed;
	}

	return '';
}

/**
 * Prioridad de avatar de usuario:
 * 1) workspaceAvatarUrl (http/https válido)
 * 2) avatar local legado
 * 3) fallback visual del componente Avatar
 */
export function resolveUserAvatarUrl(
	workspaceAvatarUrl: string | null | undefined,
	legacyAvatarUrl: string | null | undefined
): string {
	const normalizedWorkspaceAvatar = normalizeWorkspaceAvatarUrl(workspaceAvatarUrl);
	if (normalizedWorkspaceAvatar) {
		return normalizedWorkspaceAvatar;
	}
	return getBackendAssetUrl(legacyAvatarUrl);
}

/**
 * Obtiene únicamente el nombre del archivo a partir de una ruta/URL.
 */
export function getFileNameFromPath(filePath: string | null | undefined): string {
	if (!filePath) return '';

	const withoutQuery = filePath.split('?')[0].split('#')[0];
	const normalizedPath = withoutQuery.replace(/\\/g, '/');
	return normalizedPath.split('/').filter(Boolean).pop() || withoutQuery;
}

/**
 * Formatea el texto de visualización para archivos evitando mostrar rutas completas.
 */
export function getFileDisplayName(
	filePath: string | null | undefined,
	fileType?: string,
	defaultLabel = 'Seleccionar archivo'
): string {
	if (!filePath) return defaultLabel;

	const fileName = getFileNameFromPath(filePath);
	if (!fileName) return defaultLabel;
	return fileType ? `${fileName} (${fileType.toUpperCase()})` : fileName;
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type WithoutChild<T> = T extends { child?: any } ? Omit<T, "child"> : T;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type WithoutChildren<T> = T extends { children?: any } ? Omit<T, "children"> : T;
export type WithoutChildrenOrChild<T> = WithoutChildren<WithoutChild<T>>;
export type WithElementRef<T, U extends HTMLElement = HTMLElement> = T & { ref?: U | null };

/**
 * Obtiene el color del badge según el tipo de factura (SCAII Standards)
 */
export function getInvoiceTypeColor(type?: string | null): string {
	if (!type) return 'bg-gray-100 text-gray-800 dark:bg-gray-800 dark:text-gray-200';

	const normalizedType = type.toLowerCase().trim();

	// Impo tem (Rojo)
	if (normalizedType.includes('impo tem') || normalizedType === 'tem') {
		return 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200';
	}
	// Impo Def (Verde)
	if (normalizedType.includes('impo def') || normalizedType === 'def') {
		return 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200';
	}
	// Comp Mex (Morado)
	if (normalizedType.includes('comp mex') || normalizedType === 'mex') {
		return 'bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-200';
	}
	// Cam. Reg. (Azul)
	if (normalizedType.includes('cam. reg.') || normalizedType.includes('cam reg') || normalizedType === 'cr') {
		return 'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200';
	}
	// Expo. (Azul)
	if (normalizedType.includes('expo') || normalizedType === 'exdef' || normalizedType === 'pterm') {
		return 'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200';
	}
	// Imp. Rep. (Azul Claro)
	if (normalizedType.includes('imp. rep.') || normalizedType.includes('imp rep') || normalizedType === 'repar') {
		return 'bg-sky-100 text-sky-800 dark:bg-sky-900 dark:text-sky-200';
	}

	return 'bg-gray-100 text-gray-800 dark:bg-gray-800 dark:text-gray-200';
}
