import ModelProviderConfig from "@/app/workspace/providers/views/modelProviderConfig";
import FullPageLoader from "@/components/fullPageLoader";
import { Badge } from "@/components/ui/badge";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
import { DefaultNetworkConfig, DefaultPerformanceConfig } from "@/lib/constants/config";
import { ProviderIconType, RenderProviderIcon } from "@/lib/constants/icons";
import { ProviderLabels, ProviderNames } from "@/lib/constants/logs";
import {
	getErrorMessage,
	setSelectedProvider,
	useAppDispatch,
	useAppSelector,
	useCreateProviderMutation,
	useGetProvidersQuery,
	useLazyGetProviderQuery,
} from "@/lib/store";
import { KnownProvider, ModelProviderName, ProviderStatus } from "@/lib/types/config";
import { cn } from "@/lib/utils";
import { RbacOperation, RbacResource, useRbac } from "@enterprise/lib";
import { AlertCircle } from "lucide-react";
import { useNavigate } from "@tanstack/react-router";
import { useQueryState } from "nuqs";
import { useCallback, useEffect, useRef, useState } from "react";
import { toast } from "sonner";
import AddCustomProviderSheet from "./dialogs/addNewCustomProviderSheet";
import ConfirmDeleteProviderDialog from "./dialogs/confirmDeleteProviderDialog";
import ConfirmRedirectionDialog from "./dialogs/confirmRedirection";
import { AddProviderDropdown } from "./views/addProviderDropdown";
import { ProvidersEmptyState } from "./views/providersEmptyState";

export default function Providers() {
	const dispatch = useAppDispatch();
	const navigate = useNavigate();
	const hasProvidersAccess = useRbac(RbacResource.ModelProvider, RbacOperation.View);
	const hasSettingsOnly = useRbac(RbacResource.Settings, RbacOperation.View);
	const hasProviderCreateAccess = useRbac(RbacResource.ModelProvider, RbacOperation.Create);

	// Redirect Settings-only users to Custom pricing tab
	useEffect(() => {
		if (!hasProvidersAccess && hasSettingsOnly) {
			navigate({ to: "/workspace/custom-pricing", replace: true });
		}
	}, [hasProvidersAccess, hasSettingsOnly, navigate]);

	const selectedProvider = useAppSelector((state) => state.provider.selectedProvider);
	const providerFormIsDirty = useAppSelector((state) => state.provider.isDirty);

	const [showRedirectionDialog, setShowRedirectionDialog] = useState(false);
	const [showDeleteProviderDialog, setShowDeleteProviderDialog] = useState(false);
	const [pendingRedirection, setPendingRedirection] = useState<string | undefined>(undefined);
	const [showCustomProviderSheet, setShowCustomProviderSheet] = useState(false);
	const [provider, setProvider] = useQueryState("provider");

	const { data: savedProviders, isLoading: isLoadingProviders } = useGetProvidersQuery();
	const [getProvider, { isLoading: isLoadingProvider }] = useLazyGetProviderQuery();
	const [createProvider] = useCreateProviderMutation();

	const configuredProviders = (savedProviders ?? []).slice().sort((a, b) => a.name.localeCompare(b.name));
	const configuredProviderNamesArr = configuredProviders.map((p) => p.name);
	const configuredProviderNamesKey = JSON.stringify(configuredProviderNamesArr);
	const existingInSidebarNames = new Set(configuredProviders.map((p) => p.name));

	const knownProviders = ProviderNames.map((name) => ({ name }));

	useEffect(() => {
		if (!provider) return;
		const newSelectedProvider = configuredProviders.find((p) => p.name === provider);
		if (newSelectedProvider) {
			dispatch(setSelectedProvider(newSelectedProvider));
		}
		getProvider(provider)
			.unwrap()
			.then((providerInfo) => {
				dispatch(setSelectedProvider(providerInfo));
			})
			.catch((err) => {
				if (err.status === 404) {
					dispatch(
						setSelectedProvider({
							name: provider as ModelProviderName,

							concurrency_and_buffer_size: DefaultPerformanceConfig,
							network_config: DefaultNetworkConfig,
							custom_provider_config: undefined,
							proxy_config: undefined,
							send_back_raw_request: undefined,
							send_back_raw_response: undefined,
							provider_status: "error",
						}),
					);
					return;
				}
				toast.error("Something went wrong", {
					description: `We encountered an error while getting provider config: ${getErrorMessage(err)}`,
				});
			});
	}, [provider, isLoadingProviders]);

	useEffect(() => {
		if (selectedProvider || configuredProviders.length === 0 || provider) return;
		setProvider(configuredProviders[0].name);
		// eslint-disable-next-line react-hooks/exhaustive-deps
	}, [selectedProvider, configuredProviderNamesKey]);

	// When current provider is no longer configured (e.g. all keys deleted), switch to another configured provider
	useEffect(() => {
		if (!provider || configuredProviderNamesArr.length === 0) return;
		const isCurrentConfigured = configuredProviderNamesArr.includes(provider as ModelProviderName);
		if (!isCurrentConfigured) {
			setProvider(configuredProviderNamesArr[0]);
		}
		// eslint-disable-next-line react-hooks/exhaustive-deps
	}, [provider, configuredProviderNamesKey]);

	if (!hasProvidersAccess && hasSettingsOnly) {
		return <FullPageLoader />;
	}
	if (isLoadingProviders) {
		return <FullPageLoader />;
	}

	const handleSelectKnownProvider = async (name: string) => {
		try {
			await createProvider({ provider: name as ModelProviderName }).unwrap();
			setProvider(name);
		} catch (err: any) {
			if (err?.status === 409) {
				setProvider(name);
				return;
			}
			toast.error("Failed to add provider", {
				description: getErrorMessage(err),
			});
		}
	};

	if (configuredProviders.length === 0) {
		return (
			<div className="mx-auto w-full max-w-7xl">
				<ProvidersEmptyState
					addProviderDropdown={
						<AddProviderDropdown
							disabled={!hasProviderCreateAccess}
							existingInSidebar={existingInSidebarNames}
							knownProviders={knownProviders}
							onSelectKnownProvider={handleSelectKnownProvider}
							onAddCustomProvider={() => setShowCustomProviderSheet(true)}
							variant="empty"
						/>
					}
				/>
				<AddCustomProviderSheet
					show={showCustomProviderSheet}
					onClose={() => setShowCustomProviderSheet(false)}
					onSave={(providerName) => {
						setTimeout(() => setProvider(providerName), 300);
						setShowCustomProviderSheet(false);
					}}
				/>
			</div>
		);
	}

	return (
		<div className="flex h-full w-full flex-row gap-4">
			<ConfirmDeleteProviderDialog
				provider={selectedProvider!}
				show={showDeleteProviderDialog}
				onCancel={() => setShowDeleteProviderDialog(false)}
				onDelete={() => {
					const next = configuredProviders.filter((p) => p.name !== selectedProvider?.name)[0];
					setProvider(next?.name ?? null);
					setShowDeleteProviderDialog(false);
				}}
			/>
			<ConfirmRedirectionDialog
				show={showRedirectionDialog}
				onCancel={() => setShowRedirectionDialog(false)}
				onContinue={() => {
					setShowRedirectionDialog(false);
					if (pendingRedirection) setProvider(pendingRedirection);
					setPendingRedirection(undefined);
				}}
			/>
			<AddCustomProviderSheet
				show={showCustomProviderSheet}
				onClose={() => setShowCustomProviderSheet(false)}
				onSave={(providerName) => {
					setTimeout(() => setProvider(providerName), 300);
					setShowCustomProviderSheet(false);
				}}
			/>
			<div className="flex flex-col" style={{ maxHeight: "calc(100vh - 70px)", width: "300px" }}>
				<TooltipProvider>
					<div className="custom-scrollbar flex-1 overflow-y-auto">
						<div className="rounded-md bg-zinc-50/50 p-4 dark:bg-zinc-800/20">
							{/* Configured Providers (standard with keys + custom) */}
							{configuredProviders.length > 0 && (
								<div className="mb-4">
									<div className="text-muted-foreground mb-2 text-xs font-medium">Configured Providers</div>
									{configuredProviders.map((p) => {
										const isCustom = !ProviderNames.includes(p.name as KnownProvider);
										const label = isCustom ? p.name : ProviderLabels[p.name as keyof typeof ProviderLabels];
										return (
											<div
												key={p.name}
												data-testid={`provider-item-${p.name.replace(/[^a-z0-9]+/gi, "-").toLowerCase()}`}
												className={cn(
													"mb-1 flex h-8 w-full min-w-0 cursor-pointer items-center gap-2 rounded-sm border px-3 text-sm",
													selectedProvider?.name === p.name
														? "bg-secondary opacity-100 hover:opacity-100"
														: "hover:bg-secondary cursor-pointer border-transparent opacity-100 hover:border",
												)}
												onClick={(e) => {
													e.preventDefault();
													e.stopPropagation();
													if (providerFormIsDirty) {
														setPendingRedirection(p.name);
														setShowRedirectionDialog(true);
														return;
													}
													setProvider(p.name);
												}}
											>
												<RenderProviderIcon
													provider={(isCustom ? p.custom_provider_config?.base_provider_type : p.name) as ProviderIconType}
													size="sm"
													className="h-4 w-4 shrink-0"
												/>
												<TruncatedName name={label} />
												<KeyDiscoveryFailedBadge provider={p} />
												<ProviderStatusBadge status={p.provider_status} />
												{isCustom && (
													<Badge variant="secondary" className="text-muted-foreground ml-auto shrink-0 px-1.5 py-0.5 text-[10px] font-bold">
														CUSTOM
													</Badge>
												)}
											</div>
										);
									})}
								</div>
							)}
							<div className="pb-4">
								<AddProviderDropdown
									disabled={!hasProviderCreateAccess}
									existingInSidebar={existingInSidebarNames}
									knownProviders={knownProviders}
									onSelectKnownProvider={handleSelectKnownProvider}
									onAddCustomProvider={() => setShowCustomProviderSheet(true)}
								/>
							</div>
						</div>
					</div>
				</TooltipProvider>
			</div>
			{isLoadingProvider && (
				<div className="bg-muted/10 flex w-full items-center justify-center rounded-md" style={{ maxHeight: "calc(100vh - 300px)" }}>
					<FullPageLoader />
				</div>
			)}
			{!selectedProvider && (
				<div className="bg-muted/10 flex w-full items-center justify-center rounded-md" style={{ maxHeight: "calc(100vh - 300px)" }}>
					<div className="text-muted-foreground text-sm">Select a provider</div>
				</div>
			)}
			{!isLoadingProvider && selectedProvider && (
				<ModelProviderConfig provider={selectedProvider} onRequestDelete={() => setShowDeleteProviderDialog(true)} />
			)}
		</div>
	);
}

function TruncatedName({ name }: { name: string }) {
	const textRef = useRef<HTMLDivElement>(null);
	const [isTruncated, setIsTruncated] = useState(false);

	const checkTruncation = useCallback(() => {
		const el = textRef.current;
		if (el) {
			setIsTruncated(el.scrollWidth > el.clientWidth);
		}
	}, []);

	useEffect(() => {
		checkTruncation();
		window.addEventListener("resize", checkTruncation);
		return () => window.removeEventListener("resize", checkTruncation);
	}, [checkTruncation, name]);

	const inner = (
		<div ref={textRef} className="min-w-0 flex-1 truncate text-sm">
			{name}
		</div>
	);

	if (!isTruncated) return inner;

	return (
		<Tooltip>
			<TooltipTrigger asChild>{inner}</TooltipTrigger>
			<TooltipContent side="right">{name}</TooltipContent>
		</Tooltip>
	);
}

function ProviderStatusBadge({ status }: { status: ProviderStatus }) {
	return status != "active" ? (
		<Tooltip>
			<TooltipTrigger>
				<AlertCircle className="h-3 w-3" />
			</TooltipTrigger>
			<TooltipContent>{status === "error" ? "Provider could not be initialized" : "Provider is deleted"}</TooltipContent>
		</Tooltip>
	) : null;
}

function KeyDiscoveryFailedBadge({
	provider,
}: {
	provider: {
		status?: string;
		description?: string;
	};
}) {
	const providerFailed = provider.status === "list_models_failed";

	if (!providerFailed) return null;

	return (
		<Tooltip>
			<TooltipTrigger>
				<AlertCircle className="h-3 w-3" />
			</TooltipTrigger>
			<TooltipContent>{provider.description || "Provider model discovery failed."}</TooltipContent>
		</Tooltip>
	);
}