import { useCallback, useEffect, useState } from "react";
import { extractErrorMessage } from "../utils/errors";
import {
	createToolType,
	deleteToolType,
	listToolTypes,
	updateToolType,
	type CreateToolTypeRequest,
	type ReadinessProbe,
	type ToolType,
	type UpdateToolTypeRequest,
} from "../api/tool-types";
import {
	createToolDefinition,
	getToolDefinition,
	listToolDefinitions,
	updateToolDefinition,
} from "../api/tool-definitions";
import type { ToolTypeFormState } from "../components/features/tool-workshop/ToolTypeEditorPanel";

type Status = "loading" | "ready" | "error";

const defaultForm: ToolTypeFormState = {
	name: "",
	display_name: "",
	description: "",
	category: "",
	interface_type: "web",
	requires_port: true,
	default_port: "",
	definition_type: "compose",
	compose_template: "",
	dockerfile_template: "",
	readiness_command: "",
	readiness_timeout: "30",
	readiness_interval: "2",
	required_variables: "",
	startup_command: "",
};

export const useToolWorkshop = () => {
	const [status, setStatus] = useState<Status>("loading");
	const [toolTypes, setToolTypes] = useState<ToolType[]>([]);
	const [baseDefinitions, setBaseDefinitions] = useState<
		Awaited<ReturnType<typeof listToolDefinitions>>
	>([]);
	const [manifestData, setManifestData] = useState<Record<
		string,
		unknown
	> | null>(null);
	const [manifestDefinitionId, setManifestDefinitionId] = useState<
		string | null
	>(null);
	const [selectedToolTypeId, setSelectedToolTypeId] = useState<string | null>(
		null,
	);
	const [isCreating, setIsCreating] = useState(false);
	const [toolTypeForm, setToolTypeForm] = useState<ToolTypeFormState>(defaultForm);
	const [toolTypeError, setToolTypeError] = useState<string | null>(null);
	const [toolTypeDirty, setToolTypeDirty] = useState(false);

	const selectedToolType =
		(toolTypes || []).find((t) => t.id === selectedToolTypeId) || null;

	const loadData = useCallback(async () => {
		setStatus("loading");
		try {
			const [types, defs] = await Promise.all([
				listToolTypes(),
				listToolDefinitions(),
			]);
			setToolTypes(types || []);
			setBaseDefinitions((defs || []).filter((d) => d.is_base));
			setStatus("ready");
		} catch {
			setStatus("error");
		}
	}, []);

	useEffect(() => {
		void loadData();
	}, [loadData]);

	const resetToolTypeForm = () => {
		setToolTypeForm(defaultForm);
		setToolTypeError(null);
		setToolTypeDirty(false);
		setManifestData(null);
		setManifestDefinitionId(null);
	};

	const populateToolTypeForm = async (toolType: ToolType) => {
		setToolTypeForm({
			name: toolType.name,
			display_name: toolType.display_name,
			description: toolType.description || "",
			category: toolType.category || "",
			interface_type: (toolType.interface_type as "web" | "terminal") || "web",
			requires_port: toolType.requires_port ?? true,
			default_port: toolType.default_port?.toString() || "",
			definition_type:
				(toolType.definition_type as "compose" | "dockerfile" | "manifest") ||
				"compose",
			compose_template: toolType.compose_template || "",
			dockerfile_template: toolType.dockerfile_template || "",
			readiness_command: toolType.readiness_probe?.command || "",
			readiness_timeout: toolType.readiness_probe?.timeout?.toString() || "30",
			readiness_interval: toolType.readiness_probe?.interval?.toString() || "2",
			required_variables: toolType.required_variables?.join(", ") || "",
			startup_command: toolType.startup_command || "",
		});
		setToolTypeError(null);
		setToolTypeDirty(false);
		setManifestDefinitionId(toolType.manifest_id || null);

		if (toolType.definition_type === "manifest" && toolType.manifest_id) {
			try {
				const defn = await getToolDefinition(toolType.manifest_id);
				setManifestData(defn.manifest);
			} catch {
				setManifestData(null);
			}
		} else {
			setManifestData(null);
		}
	};

	const handleSelectToolType = (toolType: ToolType | null) => {
		if (toolTypeDirty) {
			if (!window.confirm("You have unsaved changes. Discard them?")) {
				return;
			}
		}
		if (toolType) {
			setSelectedToolTypeId(toolType.id);
			setIsCreating(false);
			void populateToolTypeForm(toolType);
		} else {
			setSelectedToolTypeId(null);
		}
	};

	const handleCreateNew = () => {
		if (toolTypeDirty) {
			if (!window.confirm("You have unsaved changes. Discard them?")) {
				return;
			}
		}
		setSelectedToolTypeId(null);
		setIsCreating(true);
		resetToolTypeForm();
	};

	const handleToolTypeSubmit = async (e?: React.FormEvent): Promise<boolean> => {
		e?.preventDefault();
		setToolTypeError(null);

		if (!toolTypeForm.name.trim() || !toolTypeForm.display_name.trim()) {
			setToolTypeError("Name and display name are required");
			return false;
		}

		if (
			toolTypeForm.requires_port &&
			(!toolTypeForm.default_port.trim() ||
				isNaN(Number(toolTypeForm.default_port)))
		) {
			setToolTypeError("Default port is required and must be a number");
			return false;
		}

		if (toolTypeForm.definition_type !== "manifest") {
			const template =
				toolTypeForm.definition_type === "compose"
					? toolTypeForm.compose_template
					: toolTypeForm.dockerfile_template;

			if (!template.trim()) {
				setToolTypeError(
					`${toolTypeForm.definition_type === "compose" ? "Compose" : "Dockerfile"} template is required`,
				);
				return false;
			}
		} else if (!manifestData) {
			setToolTypeError(
				"Manifest data is required for manifest definition type",
			);
			return false;
		}

		const variables = toolTypeForm.required_variables
			.split(",")
			.map((v) => v.trim())
			.filter((v) => v.length > 0);

		const readinessProbe: ReadinessProbe | undefined =
			toolTypeForm.readiness_command.trim()
				? {
						command: toolTypeForm.readiness_command.trim(),
						timeout: parseInt(toolTypeForm.readiness_timeout) || 30,
						interval: parseInt(toolTypeForm.readiness_interval) || 2,
					}
				: undefined;

		const template =
			toolTypeForm.definition_type === "compose"
				? toolTypeForm.compose_template
				: toolTypeForm.dockerfile_template;

		try {
			if (isCreating) {
				let manifestId: string | undefined;
				if (toolTypeForm.definition_type === "manifest" && manifestData) {
					const manifestPayload = {
						name: toolTypeForm.name.trim(),
						display_name: toolTypeForm.display_name.trim(),
						description: toolTypeForm.description.trim() || undefined,
						category: toolTypeForm.category.trim() || undefined,
						interface_type: toolTypeForm.interface_type,
						base_image: (manifestData.base_image as string) || undefined,
						base_definition_id:
							(manifestData.base_definition_id as string) || undefined,
						manifest: manifestData,
					};
					const newManifest = await createToolDefinition(manifestPayload);
					manifestId = newManifest.id;
				}

				const input: CreateToolTypeRequest = {
					name: toolTypeForm.name.trim(),
					display_name: toolTypeForm.display_name.trim(),
					description: toolTypeForm.description.trim() || undefined,
					category: toolTypeForm.category.trim() || undefined,
					interface_type: toolTypeForm.interface_type,
					requires_port: toolTypeForm.requires_port,
					default_port: toolTypeForm.requires_port
						? Number(toolTypeForm.default_port)
						: 0,
					definition_type: toolTypeForm.definition_type,
					manifest_id: manifestId,
					compose_template:
						toolTypeForm.definition_type === "compose" ? template : undefined,
					dockerfile_template:
						toolTypeForm.definition_type === "dockerfile"
							? template
							: undefined,
					readiness_probe: readinessProbe,
					required_variables: variables,
					startup_command: toolTypeForm.startup_command.trim() || undefined,
				};
				const newTool = await createToolType(input);
				setIsCreating(false);
				setSelectedToolTypeId(newTool.id);
				setToolTypeDirty(false);
			} else if (selectedToolType) {
				let manifestId = selectedToolType.manifest_id || undefined;
				if (toolTypeForm.definition_type === "manifest" && manifestData) {
					if (manifestId) {
						await updateToolDefinition(manifestId, {
							display_name: toolTypeForm.display_name.trim(),
							description: toolTypeForm.description.trim() || undefined,
							category: toolTypeForm.category.trim() || undefined,
							manifest: manifestData,
						});
					} else {
						const manifestPayload = {
							name: toolTypeForm.name.trim(),
							display_name: toolTypeForm.display_name.trim(),
							description: toolTypeForm.description.trim() || undefined,
							category: toolTypeForm.category.trim() || undefined,
							interface_type: toolTypeForm.interface_type,
							base_image: (manifestData.base_image as string) || undefined,
							base_definition_id:
								(manifestData.base_definition_id as string) || undefined,
							manifest: manifestData,
						};
						const newManifest = await createToolDefinition(manifestPayload);
						manifestId = newManifest.id;
					}
				}

				const input: UpdateToolTypeRequest = {
					display_name: toolTypeForm.display_name.trim(),
					description: toolTypeForm.description.trim() || undefined,
					category: toolTypeForm.category.trim() || undefined,
					interface_type: toolTypeForm.interface_type,
					requires_port: toolTypeForm.requires_port,
					default_port: toolTypeForm.requires_port
						? Number(toolTypeForm.default_port)
						: 0,
					definition_type: toolTypeForm.definition_type,
					manifest_id:
						toolTypeForm.definition_type === "manifest"
							? manifestId
							: undefined,
					compose_template:
						toolTypeForm.definition_type === "compose" ? template : undefined,
					dockerfile_template:
						toolTypeForm.definition_type === "dockerfile"
							? template
							: undefined,
					readiness_probe: readinessProbe,
					required_variables: variables,
					startup_command: toolTypeForm.startup_command.trim() || undefined,
				};
				await updateToolType(selectedToolType.id, input);
				setToolTypeDirty(false);
			}
			await loadData();
			return true;
		} catch (err) {
			setToolTypeError(extractErrorMessage(err));
			return false;
		}
	};

	const handleDeleteToolType = async (id: string) => {
		if (
			!window.confirm(
				"Delete this tool type? All associated configs will be removed.",
			)
		)
			return;
		try {
			await deleteToolType(id);
			if (selectedToolTypeId === id) {
				setSelectedToolTypeId(null);
				setIsCreating(false);
				resetToolTypeForm();
			}
			await loadData();
		} catch {
			alert("Failed to delete tool type");
		}
	};

	const handleFormChange = (changes: Partial<ToolTypeFormState>) => {
		setToolTypeForm((prev) => ({ ...prev, ...changes }));
		setToolTypeDirty(true);
	};

	const handleReset = () => {
		if (isCreating) {
			resetToolTypeForm();
		} else if (selectedToolType) {
			void populateToolTypeForm(selectedToolType);
		}
	};

	return {
		status,
		toolTypes,
		baseDefinitions,
		selectedToolType,
		selectedToolTypeId,
		isCreating,
		toolTypeForm,
		manifestData,
		manifestDefinitionId,
		toolTypeError,
		toolTypeDirty,
		loadData,
		handleSelectToolType,
		handleCreateNew,
		handleToolTypeSubmit,
		handleDeleteToolType,
		handleFormChange,
		handleReset,
		setManifestData,
		setToolTypeDirty,
	};
};
