import { useMemo, useState } from "react";
import { useParams } from "react-router-dom";
import { Alert, AlertDescription } from "@/components/ui/alert";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Switch } from "@/components/ui/switch";
import {
	useDeleteServiceInstance,
	useSaveServiceInstance,
	useServiceInstances,
	useServiceTypes,
} from "../hooks/useServices";
import type {
	ServiceInstance,
	ServiceInstanceInput,
	ServiceTypeInfo,
} from "../types";
import { SectionCard } from "../components/SectionCard";
import { ConfirmDialog } from "../components/ConfirmDialog";
import { getServiceBinding } from "../integrations/registry";

function Field({
	label,
	htmlFor,
	helper,
	children,
}: {
	label: string;
	htmlFor: string;
	helper?: string;
	children: React.ReactNode;
}) {
	return (
		<div className="flex flex-col gap-1.5">
			<Label htmlFor={htmlFor}>{label}</Label>
			{children}
			{helper ? (
				<p className="text-xs text-muted-foreground">{helper}</p>
			) : null}
		</div>
	);
}

export function ServicePage() {
	const { serviceType = "", serviceId = "" } = useParams<{
		serviceType: string;
		serviceId: string;
	}>();
	const { data: services = [] } = useServiceInstances(serviceType || undefined);
	const { data: types = [] } = useServiceTypes();
	const saveService = useSaveServiceInstance();
	const deleteService = useDeleteServiceInstance();

	const instance = useMemo(
		() => services.find((s) => s.id === serviceId),
		[services, serviceId],
	);
	const binding = getServiceBinding(serviceType);
	const typeInfo = useMemo(
		() => types.find((t) => t.service_type === serviceType),
		[types, serviceType],
	);

	const [name, setName] = useState("");
	const [enabled, setEnabled] = useState(true);
	const [draftConfig, setDraftConfig] = useState<Record<string, unknown>>({});
	const [deleteOpen, setDeleteOpen] = useState(false);
	const [hydrated, setHydrated] = useState(false);

	// Hydrate local form state once the instance loads.
	if (instance && !hydrated) {
		setName(instance.name);
		setEnabled(instance.enabled);
		setDraftConfig({ ...instance.config });
		setHydrated(true);
	}

	if (!binding) {
		return (
			<Alert>
				<AlertDescription>Unknown service type: {serviceType}</AlertDescription>
			</Alert>
		);
	}

	if (!instance) {
		return (
			<Alert>
				<AlertDescription>Service not found.</AlertDescription>
			</Alert>
		);
	}

	function buildInput(): ServiceInstanceInput {
		return {
			id: instance!.id,
			service_type: instance!.service_type,
			name,
			config: draftConfig,
			secrets: {}, // secrets are managed via the dedicated inputs below
			enabled,
		};
	}

	async function save() {
		await saveService.mutateAsync(buildInput());
	}

	return (
		<div className="flex flex-col gap-4">
			<div className="flex items-center justify-between">
				<div>
					<h2 className="text-xl font-semibold">{instance.name}</h2>
					<p className="text-sm text-muted-foreground">{binding.description}</p>
				</div>
				<Badge variant="outline">{binding.name}</Badge>
			</div>

			<SectionCard title="General">
				<div className="flex flex-col gap-3">
					<Field label="Name" htmlFor="service-name">
						<Input
							id="service-name"
							value={name}
							onChange={(e) => setName(e.target.value)}
						/>
					</Field>
					<div className="flex items-center gap-2">
						<Switch
							id="service-enabled"
							checked={enabled}
							onCheckedChange={setEnabled}
						/>
						<Label htmlFor="service-enabled">Enabled</Label>
					</div>
					<div className="flex justify-between">
						<Button onClick={save} disabled={saveService.isPending}>
							Save
						</Button>
						<Button variant="destructive" onClick={() => setDeleteOpen(true)}>
							Delete
						</Button>
					</div>
				</div>
			</SectionCard>

			<ServiceConnectionCard
				instance={instance}
				typeInfo={typeInfo}
				draftConfig={draftConfig}
				onConfigChange={setDraftConfig}
			/>

			{binding.widgets.length > 0 ? (
				<SectionCard
					title="Widgets"
					description="Widget kinds this service provides."
				>
					<div className="flex flex-col gap-2">
						{binding.widgets.map((w) => (
							<div
								key={w.kind}
								className="flex items-center justify-between rounded border p-2"
							>
								<div>
									<div className="font-medium">{w.name}</div>
									<div className="text-xs text-muted-foreground">
										{w.description}
									</div>
								</div>
								<Badge variant="outline">{w.kind}</Badge>
							</div>
						))}
						<p className="text-xs text-muted-foreground">
							Add these to the dashboard from the dashboard's edit dialog.
						</p>
					</div>
				</SectionCard>
			) : null}

			<ConfirmDialog
				open={deleteOpen}
				title="Delete service?"
				message="This removes the service and any widgets that reference it. This cannot be undone."
				confirmLabel="Delete"
				onCancel={() => setDeleteOpen(false)}
				onConfirm={() => {
					deleteService.mutate(instance.id);
					setDeleteOpen(false);
				}}
			/>
		</div>
	);
}

function ServiceConnectionCard({
	instance,
	typeInfo,
	draftConfig,
	onConfigChange,
}: {
	instance: ServiceInstance;
	typeInfo: ServiceTypeInfo | undefined;
	draftConfig: Record<string, unknown>;
	onConfigChange: (config: Record<string, unknown>) => void;
}) {
	const saveService = useSaveServiceInstance();
	// Empty-on-edit: local state starts blank; a blank field means "keep existing".
	const [draftSecrets, setDraftSecrets] = useState<Record<string, string>>({});

	const properties =
		(
			(typeInfo?.config_schema ?? {}) as {
				properties?: Record<
					string,
					{ type?: string; description?: string; default?: unknown }
				>;
			}
		).properties ?? {};
	const configEntries: Array<
		[string, { type?: string; description?: string }]
	> =
		Object.keys(properties).length > 0
			? Object.entries(properties).map(([key, schema]) => [
					key,
					{ type: schema?.type, description: schema?.description },
				])
			: Object.entries(instance.config).map(([key, value]) => [
					key,
					{ type: typeof value === "number" ? "integer" : "string" },
				]);

	return (
		<SectionCard
			title="Connection"
			description="Edit non-secret connection config and secret values."
		>
			<div className="flex flex-col gap-3">
				{configEntries.length === 0 ? (
					<p className="text-sm text-muted-foreground">No connection config.</p>
				) : (
					<div className="flex flex-col gap-3">
						{configEntries.map(([key, schema]) => {
							const isNumber =
								schema.type === "integer" || schema.type === "number";
							return (
								<Field
									key={key}
									label={key}
									htmlFor={`cfg-${key}`}
									helper={schema.description}
								>
									<Input
										id={`cfg-${key}`}
										type={isNumber ? "number" : "text"}
										value={String(draftConfig[key] ?? "")}
										onChange={(e) =>
											onConfigChange({
												...draftConfig,
												[key]: isNumber
													? e.target.value === ""
														? undefined
														: Number(e.target.value)
													: e.target.value,
											})
										}
									/>
								</Field>
							);
						})}
					</div>
				)}

				{Object.keys(instance.secrets_set).length === 0 ? (
					<p className="text-sm text-muted-foreground">No secret fields.</p>
				) : (
					<div className="flex flex-col gap-3">
						{Object.entries(instance.secrets_set).map(([key, isSet]) => (
							<div key={key} className="flex flex-col gap-1.5">
								<Field
									label={key}
									htmlFor={`secret-${key}`}
									helper="Leave blank to keep the current value."
								>
									<Input
										id={`secret-${key}`}
										type="password"
										placeholder={isSet ? "•••••• (set)" : "Not set"}
										value={draftSecrets[key] ?? ""}
										onChange={(e) =>
											setDraftSecrets({
												...draftSecrets,
												[key]: e.target.value,
											})
										}
									/>
								</Field>
								{isSet ? <Badge variant="secondary">set</Badge> : null}
							</div>
						))}
					</div>
				)}

				<Button
					onClick={() => {
						const onlyChanged = Object.fromEntries(
							Object.entries(draftSecrets).filter(([, v]) => v !== ""),
						);
						saveService.mutate({
							id: instance.id,
							service_type: instance.service_type,
							name: instance.name,
							config: draftConfig,
							secrets: onlyChanged,
							enabled: instance.enabled,
						});
						setDraftSecrets({});
					}}
				>
					Update connection
				</Button>
			</div>
		</SectionCard>
	);
}
