import { useCallback, useEffect, useState } from "react";
import { extractErrorMessage } from "../utils/errors";
import {
	createConfigProfile,
	deleteConfigProfile,
	listConfigProfiles,
	previewConfigProfile,
	updateConfigProfile,
	updateProfileIncludes,
	type ConfigProfile,
	type CreateConfigProfileRequest,
	type ResolvedProfile,
} from "../api/config-profiles";
import { listProjects } from "../api/projects";
import { listToolTypes, type ToolType } from "../api/tool-types";
import type { ProjectWithRepos } from "../types";

type Status = "loading" | "ready" | "error";
type SaveStatus = "idle" | "saving" | "saved" | "error";

const defaultForm: CreateConfigProfileRequest = {
	name: "",
	description: "",
	env_vars: {},
	runtime_hints: {},
	mounts: [],
	git_mounts: [],
	files: {},
	is_default: false,
};

export const useConfigProfiles = () => {
	const [status, setStatus] = useState<Status>("loading");
	const [profiles, setProfiles] = useState<ConfigProfile[]>([]);
	const [projects, setProjects] = useState<ProjectWithRepos[]>([]);
	const [toolTypes, setToolTypes] = useState<ToolType[]>([]);
	const [selectedProfileId, setSelectedProfileId] = useState<string | null>(null);
	const [isCreating, setIsCreating] = useState(false);
	const [saveStatus, setSaveStatus] = useState<SaveStatus>("idle");
	const [error, setError] = useState<string | null>(null);
	const [previewData, setPreviewData] = useState<ResolvedProfile | null>(null);
	const [previewingId, setPreviewingId] = useState<string | null>(null);
	const [formData, setFormData] = useState<CreateConfigProfileRequest>(defaultForm);
	const [includedProfileIds, setIncludedProfileIds] = useState<string[]>([]);
	const [dragOverIndex, setDragOverIndex] = useState<number | null>(null);

	const selectedProfile = profiles.find((p) => p.id === selectedProfileId) || null;

	const loadData = useCallback(async () => {
		setStatus("loading");
		try {
			const [profs, projs, types] = await Promise.all([
				listConfigProfiles(),
				listProjects(),
				listToolTypes(),
			]);
			setProfiles(profs || []);
			setProjects(projs || []);
			setToolTypes(types || []);
			setStatus("ready");
		} catch {
			setStatus("error");
		}
	}, []);

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

	const resetForm = () => {
		setFormData(defaultForm);
		setIncludedProfileIds([]);
		setError(null);
		setSaveStatus("idle");
		setPreviewData(null);
	};

	const populateForm = (profile: ConfigProfile) => {
		setFormData({
			name: profile.name,
			description: profile.description || undefined,
			project_id: profile.project_id || undefined,
			tool_type_id: profile.tool_type_id || undefined,
			env_vars: profile.env_vars,
			runtime_hints: profile.runtime_hints,
			mounts: profile.mounts,
			git_mounts: profile.git_mounts || [],
			files: profile.files,
			is_default: profile.is_default,
		});
		setIncludedProfileIds(
			profile.includes.map((inc: { included_profile_id: string }) => inc.included_profile_id),
		);
		setError(null);
		setSaveStatus("idle");
		setPreviewData(null);
	};

	const handleSelectProfile = (profile: ConfigProfile | null) => {
		if (profile) {
			setSelectedProfileId(profile.id);
			setIsCreating(false);
			populateForm(profile);
		} else {
			setSelectedProfileId(null);
		}
	};

	const handleCreateNew = () => {
		setSelectedProfileId(null);
		setIsCreating(true);
		resetForm();
	};

	const getIncludedProfile = (id: string): ConfigProfile | undefined =>
		profiles.find((p) => p.id === id);

	const getScopeLabel = (profile: ConfigProfile): string => {
		if (profile.project_id && profile.tool_type_id) return "Project + Tool";
		if (profile.project_id) return "Project";
		if (profile.tool_type_id) return "Tool";
		return "Global";
	};

	const wouldCreateCycle = (
		profileId: string,
		targetId: string,
		visited = new Set<string>(),
	): boolean => {
		if (visited.has(targetId)) return true;
		const target = getIncludedProfile(targetId);
		if (!target) return false;
		const nextVisited = new Set(visited);
		nextVisited.add(targetId);
		for (const inc of target.includes) {
			if (
				inc.included_profile_id === profileId ||
				wouldCreateCycle(profileId, inc.included_profile_id, nextVisited)
			) {
				return true;
			}
		}
		return false;
	};

	const availableProfilesForInclude = (): ConfigProfile[] => {
		const currentId = selectedProfile?.id;
		if (!currentId) return [];
		return profiles.filter((p) => {
			if (p.id === currentId) return false;
			if (includedProfileIds.includes(p.id)) return false;
			if (wouldCreateCycle(currentId, p.id)) return false;
			return true;
		});
	};

	const addInclude = (profileId: string) => {
		setIncludedProfileIds((prev) => [...prev, profileId]);
	};

	const removeInclude = (index: number) => {
		setIncludedProfileIds((prev) => prev.filter((_, i) => i !== index));
	};

	const handleDragStart = (e: React.DragEvent, index: number) => {
		e.dataTransfer.setData("text/plain", String(index));
		e.dataTransfer.effectAllowed = "move";
	};

	const handleDragOver = (e: React.DragEvent, index: number) => {
		e.preventDefault();
		e.dataTransfer.dropEffect = "move";
		setDragOverIndex(index);
	};

	const handleDragLeave = () => {
		setDragOverIndex(null);
	};

	const handleDrop = (e: React.DragEvent, dropIndex: number) => {
		e.preventDefault();
		const dragIndex = Number(e.dataTransfer.getData("text/plain"));
		if (dragIndex === dropIndex) {
			setDragOverIndex(null);
			return;
		}
		setIncludedProfileIds((prev) => {
			const newOrder = [...prev];
			const [removed] = newOrder.splice(dragIndex, 1);
			newOrder.splice(dropIndex, 0, removed);
			return newOrder;
		});
		setDragOverIndex(null);
	};

	const handleSubmit = async (e?: React.FormEvent): Promise<boolean> => {
		e?.preventDefault();
		setError(null);
		setSaveStatus("saving");

		if (!formData.name?.trim()) {
			setError("Name is required");
			setSaveStatus("error");
			return false;
		}

		try {
			if (isCreating) {
				const newProfile = await createConfigProfile(formData);
				if (includedProfileIds.length > 0) {
					await updateProfileIncludes(newProfile.id, { includes: includedProfileIds });
				}
				setIsCreating(false);
				setSelectedProfileId(newProfile.id);
				setSaveStatus("saved");
				await loadData();
				const refreshed = (await listConfigProfiles()).find((p) => p.id === newProfile.id);
				if (refreshed) populateForm(refreshed);
			} else if (selectedProfile) {
				await updateConfigProfile(selectedProfile.id, formData);
				await updateProfileIncludes(selectedProfile.id, { includes: includedProfileIds });
				setSaveStatus("saved");
				await loadData();
				const refreshed = (await listConfigProfiles()).find((p) => p.id === selectedProfile.id);
				if (refreshed) populateForm(refreshed);
			}
			return true;
		} catch (err) {
			setError(extractErrorMessage(err));
			setSaveStatus("error");
			return false;
		}
	};

	const handleDelete = async (id: string) => {
		if (!window.confirm("Are you sure you want to delete this config profile?")) return;
		try {
			await deleteConfigProfile(id);
			if (selectedProfileId === id) {
				setSelectedProfileId(null);
				setIsCreating(false);
				resetForm();
			}
			await loadData();
		} catch {
			alert("Failed to delete config profile");
		}
	};

	const handlePreview = async (id: string) => {
		try {
			setPreviewingId(id);
			const data = await previewConfigProfile(id);
			setPreviewData(data);
		} catch {
			setError("Failed to preview config profile");
		} finally {
			setPreviewingId(null);
		}
	};

	const updateFormField = <K extends keyof CreateConfigProfileRequest>(
		key: K,
		value: CreateConfigProfileRequest[K],
	) => {
		setFormData((prev) => ({ ...prev, [key]: value }));
		setSaveStatus("idle");
	};

	const addEnvVar = () => {
		setFormData((prev) => ({ ...prev, env_vars: { ...prev.env_vars, "": "" } }));
		setSaveStatus("idle");
	};

	const updateEnvVar = (oldKey: string, newKey: string, value: string) => {
		setFormData((prev) => {
			const envVars = { ...prev.env_vars };
			if (oldKey !== newKey) delete envVars[oldKey];
			envVars[newKey] = value;
			return { ...prev, env_vars: envVars };
		});
		setSaveStatus("idle");
	};

	const removeEnvVar = (key: string) => {
		setFormData((prev) => {
			const envVars = { ...prev.env_vars };
			delete envVars[key];
			return { ...prev, env_vars: envVars };
		});
		setSaveStatus("idle");
	};

	const addFile = () => {
		setFormData((prev) => ({ ...prev, files: { ...prev.files, "": "" } }));
		setSaveStatus("idle");
	};

	const updateFile = (oldPath: string, newPath: string, content: string) => {
		setFormData((prev) => {
			const files = { ...prev.files };
			if (oldPath !== newPath) delete files[oldPath];
			files[newPath] = content;
			return { ...prev, files };
		});
		setSaveStatus("idle");
	};

	const removeFile = (path: string) => {
		setFormData((prev) => {
			const files = { ...prev.files };
			delete files[path];
			return { ...prev, files };
		});
		setSaveStatus("idle");
	};

	const addMount = () => {
		setFormData((prev) => ({
			...prev,
			mounts: [...(prev.mounts || []), { target: "/", mode: "rw", files: {} }],
		}));
		setSaveStatus("idle");
	};

	const updateMount = (index: number, updates: Partial<ConfigProfile["mounts"][0]>) => {
		setFormData((prev) => {
			const mounts = [...(prev.mounts || [])];
			mounts[index] = { ...mounts[index], ...updates };
			return { ...prev, mounts };
		});
		setSaveStatus("idle");
	};

	const removeMount = (index: number) => {
		setFormData((prev) => {
			const mounts = [...(prev.mounts || [])];
			mounts.splice(index, 1);
			return { ...prev, mounts };
		});
		setSaveStatus("idle");
	};

	const addMountFile = (mountIndex: number) => {
		setFormData((prev) => {
			const mounts = [...(prev.mounts || [])];
			mounts[mountIndex] = {
				...mounts[mountIndex],
				files: { ...mounts[mountIndex].files, "": "" },
			};
			return { ...prev, mounts };
		});
		setSaveStatus("idle");
	};

	const updateMountFile = (
		mountIndex: number,
		oldPath: string,
		newPath: string,
		content: string,
	) => {
		setFormData((prev) => {
			const mounts = [...(prev.mounts || [])];
			const files = { ...mounts[mountIndex].files };
			if (oldPath !== newPath) delete files[oldPath];
			files[newPath] = content;
			mounts[mountIndex] = { ...mounts[mountIndex], files };
			return { ...prev, mounts };
		});
		setSaveStatus("idle");
	};

	const removeMountFile = (mountIndex: number, path: string) => {
		setFormData((prev) => {
			const mounts = [...(prev.mounts || [])];
			const files = { ...mounts[mountIndex].files };
			delete files[path];
			mounts[mountIndex] = { ...mounts[mountIndex], files };
			return { ...prev, mounts };
		});
		setSaveStatus("idle");
	};

	return {
		status,
		profiles,
		projects,
		toolTypes,
		selectedProfile,
		selectedProfileId,
		isCreating,
		saveStatus,
		error,
		previewData,
		previewingId,
		formData,
		includedProfileIds,
		dragOverIndex,
		loadData,
		handleSelectProfile,
		handleCreateNew,
		handleSubmit,
		handleDelete,
		handlePreview,
		updateFormField,
		addEnvVar,
		updateEnvVar,
		removeEnvVar,
		addFile,
		updateFile,
		removeFile,
		addMount,
		updateMount,
		removeMount,
		addMountFile,
		updateMountFile,
		removeMountFile,
		getIncludedProfile,
		getScopeLabel,
		availableProfilesForInclude,
		addInclude,
		removeInclude,
		handleDragStart,
		handleDragOver,
		handleDragLeave,
		handleDrop,
		setPreviewData,
		setFormData,
		setSaveStatus,
		setIncludedProfileIds,
		populateForm,
	};
};
