import { useState, useEffect } from "react";
import { Icon } from "../../icon";
import { validateGitUrl } from "../../../api/config-profiles";
import type { GitMount, GitMountMapping } from "../../../api/config-profiles";

interface GitMountEditorProps {
	mounts: GitMount[];
	onChange: (mounts: GitMount[]) => void;
}

function normalizeMount(mount: GitMount): GitMount {
	// Auto-convert legacy source_path + target_path to mappings
	if (
		(!mount.mappings || mount.mappings.length === 0) &&
		mount.source_path !== undefined &&
		mount.target_path !== undefined
	) {
		return {
			remote_url: mount.remote_url,
			branch: mount.branch,
			mappings: [
				{
					source_path: mount.source_path || ".",
					target_path: mount.target_path,
				},
			],
		};
	}
	return mount;
}

function normalizeMounts(mounts: GitMount[]): GitMount[] {
	return mounts.map(normalizeMount);
}

export const GitMountEditor = ({
	mounts,
	onChange,
}: GitMountEditorProps) => {
	const [normalizedMounts, setNormalizedMounts] = useState<GitMount[]>(() =>
		normalizeMounts(mounts),
	);
	const [editingIndex, setEditingIndex] = useState<number | null>(null);
	const [isAdding, setIsAdding] = useState(false);

	useEffect(() => {
		setNormalizedMounts(normalizeMounts(mounts));
	}, [mounts]);

	const handleAdd = (mount: GitMount) => {
		const updated = [...normalizedMounts, normalizeMount(mount)];
		setNormalizedMounts(updated);
		onChange(updated);
		setIsAdding(false);
	};

	const handleUpdate = (index: number, updated: GitMount) => {
		const updatedMounts = [...normalizedMounts];
		updatedMounts[index] = normalizeMount(updated);
		setNormalizedMounts(updatedMounts);
		onChange(updatedMounts);
		setEditingIndex(null);
	};

	const handleRemove = (index: number) => {
		const updated = normalizedMounts.filter((_, i) => i !== index);
		setNormalizedMounts(updated);
		onChange(updated);
	};

	return (
		<div className="git-mount-editor">
			<h4 className="m-0 mb-2">Git Mounts</h4>
			<p className="muted text-sm mb-3 m-0">
				Clone a repository once and mount multiple directories from it.
			</p>

			{normalizedMounts.length > 0 && (
				<div className="git-mount-list mb-4">
					{normalizedMounts.map((mount, index) => (
						<div key={index} className="card-md">
							{editingIndex === index ? (
								<GitMountForm
									mount={mount}
									onSave={(updated) => handleUpdate(index, updated)}
									onCancel={() => setEditingIndex(null)}
								/>
							) : (
								<div>
									<div className="row justify-between items-start mb-2">
										<div className="min-w-0 flex-1">
											<div className="font-semibold text-base mb-1">
												{mount.remote_url}
												{mount.branch && (
													<span className="muted font-normal ml-2">
														@{mount.branch}
													</span>
												)}
											</div>
											<div className="stack stack-sm">
												{mount.mappings?.map((m, mi) => (
													<div
														key={mi}
														className="text-sm muted font-mono"
													>
														{m.source_path || "."} → {m.target_path}
													</div>
												))}
											</div>
										</div>
										<div className="row row-sm flex-none">
											<button
												type="button"
												className="ghost-button small"
												onClick={() => setEditingIndex(index)}
												title="Edit"
											>
												<Icon name="edit" size="sm" />
											</button>
											<button
												type="button"
												className="ghost-button small"
												onClick={() => handleRemove(index)}
												title="Remove"
											>
												<Icon name="delete" size="sm" />
											</button>
										</div>
									</div>
								</div>
							)}
						</div>
					))}
				</div>
			)}

			{isAdding ? (
				<div className="card-md">
					<GitMountForm
						mount={{
							remote_url: "",
							branch: "",
							mappings: [{ source_path: ".", target_path: "" }],
						}}
						onSave={handleAdd}
						onCancel={() => setIsAdding(false)}
					/>
				</div>
			) : (
				<button
					type="button"
					className="secondary-button"
					onClick={() => setIsAdding(true)}
				>
					<Icon name="add" size="sm" />
					Add Git Mount
				</button>
			)}
		</div>
	);
};

interface GitMountFormProps {
	mount: GitMount;
	onSave: (mount: GitMount) => void;
	onCancel: () => void;
}

type ValidationState =
	| { status: "idle" }
	| { status: "loading" }
	| { status: "valid"; branches: string[]; defaultBranch: string }
	| { status: "suggestion"; suggestedUrl: string; message: string }
	| { status: "invalid"; message: string };

const GitMountForm = ({
	mount,
	onSave,
	onCancel,
}: GitMountFormProps) => {
	const [remoteUrl, setRemoteUrl] = useState(mount.remote_url);
	const [branch, setBranch] = useState(mount.branch || "");
	const [mappings, setMappings] = useState<GitMountMapping[]>(
		mount.mappings?.length
			? mount.mappings
			: [{ source_path: ".", target_path: "" }],
	);
	const [errors, setErrors] = useState<Record<string, string>>({});
	const [validation, setValidation] = useState<ValidationState>({
		status: "idle",
	});

	const isUrlValidated =
		validation.status === "valid" ||
		(validation.status === "idle" && mount.remote_url.length > 0);

	const handleCheckUrl = async () => {
		if (!remoteUrl.trim()) {
			setErrors((prev) => ({ ...prev, remote_url: "Git URL is required" }));
			return;
		}
		setValidation({ status: "loading" });
		setErrors((prev) => {
			const next = { ...prev };
			delete next.remote_url;
			return next;
		});
		try {
			const result = await validateGitUrl(remoteUrl.trim());
			if (result.valid && result.branches) {
				setValidation({
					status: "valid",
					branches: result.branches,
					defaultBranch: result.default_branch || "main",
				});
				if (!branch) {
					setBranch(result.default_branch || "main");
				}
				if (result.suggested_url && result.suggested_url !== remoteUrl.trim()) {
					setRemoteUrl(result.suggested_url);
				}
			} else if (result.suggested_url) {
				setValidation({
					status: "suggestion",
					suggestedUrl: result.suggested_url,
					message: result.error || "URL needs correction",
				});
			} else {
				setValidation({
					status: "invalid",
					message: result.error || "Invalid repository URL",
				});
			}
		} catch {
			setValidation({
				status: "invalid",
				message: "Failed to validate URL. Please try again.",
			});
		}
	};

	const applySuggestion = () => {
		if (validation.status === "suggestion") {
			setRemoteUrl(validation.suggestedUrl);
			setValidation({ status: "idle" });
		}
	};

	const validate = (): boolean => {
		const newErrors: Record<string, string> = {};

		if (!remoteUrl.trim()) {
			newErrors.remote_url = "Git URL is required";
		} else if (
			!remoteUrl.startsWith("http://") &&
			!remoteUrl.startsWith("https://") &&
			!remoteUrl.startsWith("git@") &&
			!remoteUrl.startsWith("ssh://")
		) {
			newErrors.remote_url =
				"Must be a valid git URL (https://, git@, or ssh://)";
		}

		mappings.forEach((m, i) => {
			if (!m.target_path.trim()) {
				newErrors[`mapping_${i}_target`] = "Target path is required";
			}
			if (m.source_path.includes("..")) {
				newErrors[`mapping_${i}_source`] = "Source path cannot contain ..";
			}
			if (m.target_path.includes("..")) {
				newErrors[`mapping_${i}_target`] = "Target path cannot contain ..";
			}
		});

		setErrors(newErrors);
		return Object.keys(newErrors).length === 0;
	};

	const handleSubmit = () => {
		if (!validate()) return;
		onSave({
			remote_url: remoteUrl.trim(),
			branch: branch.trim() || undefined,
			mappings: mappings.map((m) => ({
				source_path: m.source_path.trim() || ".",
				target_path: m.target_path.trim(),
			})),
		});
	};

	const addMapping = () => {
		setMappings((prev) => [...prev, { source_path: ".", target_path: "" }]);
	};

	const updateMapping = (
		index: number,
		field: keyof GitMountMapping,
		value: string,
	) => {
		setMappings((prev) => {
			const next = [...prev];
			next[index] = { ...next[index], [field]: value };
			return next;
		});
		if (errors[`mapping_${index}_${field}`]) {
			setErrors((prev) => {
				const next = { ...prev };
				delete next[`mapping_${index}_${field}`];
				return next;
			});
		}
	};

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

	return (
		<div className="stack stack-md">
			<div className="form-row row-sm items-start">
				<div className="form-group flex-2">
					<label className="text-sm font-medium">Repository URL</label>
					<div className="row row-sm">
						<input
							type="text"
							value={remoteUrl}
							onChange={(e) => {
								setRemoteUrl(e.target.value);
								setValidation({ status: "idle" });
								if (errors.remote_url) {
									setErrors((prev) => {
										const next = { ...prev };
										delete next.remote_url;
										return next;
									});
								}
							}}
							placeholder="https://github.com/user/repo.git"
							className={`form-input ${errors.remote_url ? "error" : ""}`}
						/>
						<button
							type="button"
							className="secondary-button small"
							onClick={handleCheckUrl}
							disabled={validation.status === "loading"}
						>
							{validation.status === "loading" ? (
								<Icon name="loading" size="sm" />
							) : (
								"Check"
							)}
						</button>
					</div>
					{errors.remote_url && (
						<span className="text-error">{errors.remote_url}</span>
					)}
					{validation.status === "valid" && (
						<span className="validation-status valid">
							Repository is accessible (
							{
								(validation as Extract<ValidationState, { status: "valid" }>)
									.branches.length
								}{" "}
							branches)
						</span>
					)}
					{validation.status === "suggestion" && (
						<div className="url-suggestion">
							<span>{validation.message}</span>
							<div className="suggestion-actions">
								<code className="suggested-url">{validation.suggestedUrl}</code>
								<button
									type="button"
									className="secondary-button small"
									onClick={applySuggestion}
								>
									Use this
								</button>
							</div>
						</div>
					)}
					{validation.status === "invalid" && (
						<span className="validation-status invalid">
							{validation.message}
						</span>
					)}
				</div>
				<div className="form-group flex-1">
					<label className="text-sm font-medium">Branch</label>
					{validation.status === "valid" ? (
						<select
							value={branch}
							onChange={(e) => setBranch(e.target.value)}
							className="form-input"
						>
							{(
								validation as Extract<ValidationState, { status: "valid" }>
							).branches.map((b) => (
								<option key={b} value={b}>
									{b}
								</option>
							))}
						</select>
					) : (
						<input
							type="text"
							value={branch}
							onChange={(e) => setBranch(e.target.value)}
							placeholder="main"
							className="form-input"
							disabled={!isUrlValidated}
						/>
					)}
				</div>
			</div>

			<div
				className="stack stack-sm"
				style={{
					opacity: isUrlValidated ? 1 : 0.5,
					pointerEvents: isUrlValidated ? "auto" : "none",
				}}
			>
				<label className="text-sm font-medium">Mappings</label>
				<p className="muted text-sm m-0">
					Source paths within the repo and where to mount them in the container.
					{!isUrlValidated && (
						<span style={{ color: "var(--warning)" }}>
							{" "}
							Validate the URL first.
						</span>
					)}
				</p>
				<div className="stack stack-sm">
					{mappings.map((mapping, index) => (
						<div
							key={index}
							className="form-row row-sm items-start"
						>
							<input
								type="text"
								value={mapping.source_path}
								onChange={(e) =>
									updateMapping(index, "source_path", e.target.value)
								}
								placeholder="packages/api"
								className={`form-input ${errors[`mapping_${index}_source`] ? "error" : ""}`}
							/>
							<span className="text-sm muted py-2">→</span>
							<input
								type="text"
								value={mapping.target_path}
								onChange={(e) =>
									updateMapping(index, "target_path", e.target.value)
								}
								placeholder="/app/api"
								className={`form-input ${errors[`mapping_${index}_target`] ? "error" : ""}`}
							/>
							{mappings.length > 1 && (
								<button
									type="button"
									className="ghost-button small"
									onClick={() => removeMapping(index)}
									title="Remove mapping"
								>
									<Icon name="delete" size="sm" />
								</button>
							)}
							{errors[`mapping_${index}_source`] && (
								<span className="text-error">
									{errors[`mapping_${index}_source`]}
								</span>
							)}
							{errors[`mapping_${index}_target`] && (
								<span className="text-error">
									{errors[`mapping_${index}_target`]}
								</span>
							)}
						</div>
					))}
				</div>
				<button
					type="button"
					className="secondary-button small"
					onClick={addMapping}
				>
					<Icon name="add" size="sm" />
					Add Mapping
				</button>
			</div>

			<div className="form-actions row-sm mt-2">
				<button type="button" className="primary-button" onClick={handleSubmit}>
					Save
				</button>
				<button type="button" className="secondary-button" onClick={onCancel}>
					Cancel
				</button>
			</div>
		</div>
	);
};
