import { A, useNavigate } from '@solidjs/router';
import { createQuery, useQueryClient } from '@tanstack/solid-query';
import { BookPlus, LoaderCircle } from 'lucide-solid';
import { For, Show, createEffect, createSignal, type Component } from 'solid-js';

import { Avatar } from '../../components/common';
import { createRepo, listUserKnots, listRepoRecords } from '../../lib/api/repos';
import { resolveActor } from '../../lib/api/identity';
import { useAuth } from '../../lib/auth';
import { getErrorMessage } from '../../lib/repo-utils';

export const validateRepoName = (name: string): string | null => {
	if (name.length === 0) {
		return 'repository name cannot be empty';
	}
	if (name.length > 100) {
		return 'repository name must be 100 characters or fewer';
	}
	if (name.includes('/') || name.includes('\\')) {
		return 'repository name contains invalid path characters';
	}
	if (name.startsWith('.') || name.endsWith('.')) {
		return 'repository name contains invalid path sequence';
	}
	if (name.includes('..')) {
		return 'repository name cannot contain sequential dots';
	}
	const validChars = /^[a-zA-Z0-9\-_.]+$/;
	if (!validChars.test(name)) {
		return 'repository name can only contain alphanumeric characters, periods, hyphens, and underscores';
	}
	if (name.toLowerCase() === 'self') {
		return 'repository name "self" is reserved';
	}
	return null;
};

export const NewRepoPage: Component = () => {
	const auth = useAuth();
	const navigate = useNavigate();
	const queryClient = useQueryClient();

	const [name, setName] = createSignal('');
	const [description, setDescription] = createSignal('');
	const [branch, setBranch] = createSignal('main');
	const [selectedKnot, setSelectedKnot] = createSignal('');
	
	const [saving, setSaving] = createSignal(false);
	const [error, setError] = createSignal<string | null>(null);

	const viewerQuery = createQuery(() => ({
		queryKey: ['viewer', auth.currentDid()],
		enabled: Boolean(auth.currentDid()),
		queryFn: async () => resolveActor(auth.currentDid()!),
	}));

	const knotsQuery = createQuery(() => ({
		queryKey: ['knots', auth.currentDid()],
		enabled: Boolean(auth.currentDid()),
		queryFn: async () => listUserKnots(auth.currentDid()!),
	}));

	// Automatically select the knot if there is only one
	createEffect(() => {
		const knots = knotsQuery.data;
		if (knots && knots.length === 1) {
			setSelectedKnot(knots[0]);
		}
	});

	const handleSubmit = async (e: SubmitEvent) => {
		e.preventDefault();
		const agent = auth.agent();
		if (!agent) return;

		const repoName = name().trim();
		const nameError = validateRepoName(repoName);
		if (nameError) {
			setError(nameError);
			return;
		}

		const knot = selectedKnot();
		if (!knot) {
			setError('please select a knot.');
			return;
		}

		setSaving(true);
		setError(null);

		try {
			// First check if the repository already exists for this user
			const existingRecords = await queryClient.fetchQuery({
				queryKey: ['profile-repos', auth.currentDid()],
				queryFn: () => listRepoRecords(auth.currentDid()!),
			});

			const cleanedName = repoName.endsWith('.git') ? repoName.slice(0, -4) : repoName;
			const rkey = cleanedName.toLowerCase();
			const exists = existingRecords.some(
				(r) => r.rkey === rkey || (r.value.name && r.value.name.toLowerCase() === rkey)
			);

			if (exists) {
				setError(`you already have a repository named "${cleanedName}".`);
				setSaving(false);
				return;
			}

			const result = await createRepo(agent, {
				name: repoName,
				description: description(),
				defaultBranch: branch() || 'main',
				knot: knot,
			});

			// Invalidate repos query for the current user
			await queryClient.invalidateQueries({
				queryKey: ['profile-repos', auth.currentDid()],
			});

			// Navigate to the newly created repository
			const handle = viewerQuery.data?.handle || auth.currentDid();
			navigate(`/${handle}/${result.rkey}`);
		} catch (err) {
			setError(getErrorMessage(err));
		} finally {
			setSaving(false);
		}
	};

	return (
		<Show
			when={auth.currentDid()}
			fallback={
				<div class="bg-amber-50 dark:bg-amber-900 border border-amber-500 rounded p-4 relative flex gap-2 items-center dark:text-white">
					please log in to create a new repository.
				</div>
			}
		>
			<div class="grid grid-cols-12 dark:text-white">
				<div class="col-span-full md:col-start-3 md:col-span-8 px-4 py-1 mb-2">
					<h1 class="text-xl font-bold dark:text-white mb-1">create a new repository</h1>
					<p class="text-gray-600 dark:text-gray-400">
						repositories contain a project's files and version history. all repositories are publicly accessible.
					</p>
				</div>

				<div class="col-span-full md:col-start-3 md:col-span-8 bg-white dark:bg-gray-800 drop-shadow-sm rounded p-4 md:px-6 border border-gray-200 dark:border-gray-700">
					<form onSubmit={handleSubmit}>
						{error() && <p class="text-red-500 dark:text-red-400 text-sm mb-3">{error()}</p>}

						{/* Step 1 */}
						<div class="untangled-timeline-step untangled-timeline-step-1">
							<div class="untangled-timeline-circle">
								<div class="untangled-timeline-circle-inner">
									1
								</div>
							</div>

							<div class="flex-1 pb-6 pt-1">
								<h2 class="text-lg font-medium dark:text-white">general</h2>
								<div class="text-sm text-gray-500 dark:text-gray-400 mb-3">basic repository information.</div>

								<div class="space-y-3">
									{/* Repository Name */}
									<div>
										<label class="block text-sm font-bold dark:text-white mb-1">
											REPOSITORY NAME
										</label>
										<div class="flex flex-col md:flex-row md:items-center w-full">
											<div class="shrink-0 hidden md:flex items-center px-3 py-2 gap-1.5 text-sm text-gray-700 dark:text-gray-300 border border-r-0 border-gray-300 dark:border-gray-600 rounded-l bg-gray-50 dark:bg-gray-700 h-[38px]">
												<Avatar did={auth.currentDid()!} size="size-5" />
												<span>{viewerQuery.data?.handle || auth.currentDid()}</span>
											</div>
											<input
												type="text"
												id="name"
												name="name"
												value={name()}
												onInput={(e) => setName(e.currentTarget.value)}
												required
												class="flex-1 md:rounded-r md:rounded-l-none rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-900 px-3 py-2 text-sm text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-1 focus:ring-blue-500 focus:border-blue-500 h-[38px]"
												placeholder="repository-name"
											/>
										</div>
										<p class="text-sm text-gray-500 dark:text-gray-400 mt-1">
											choose a unique, descriptive name for your repository. use letters, numbers, and hyphens.
										</p>
									</div>

									{/* Description */}
									<div class="pt-2">
										<label for="description" class="block text-sm font-bold dark:text-white mb-1">
											DESCRIPTION
										</label>
										<input
											type="text"
											id="description"
											name="description"
											value={description()}
											onInput={(e) => setDescription(e.currentTarget.value)}
											maxlength="140"
											class="w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-900 px-3 py-2 text-sm text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-1 focus:ring-blue-500 focus:border-blue-500 h-[38px]"
											placeholder="a brief description of your project..."
										/>
										<p class="text-sm text-gray-500 dark:text-gray-400 mt-1">
											optional. a short description to help others understand what your project does (max 140 characters).
										</p>
									</div>
								</div>
							</div>
						</div>

						{/* Step 2 */}
						<div class="untangled-timeline-step untangled-timeline-step-2">
							<div class="untangled-timeline-circle">
								<div class="untangled-timeline-circle-inner">
									2
								</div>
							</div>

							<div class="flex-1 pt-1">
								<h2 class="text-lg font-medium dark:text-white">configuration</h2>
								<div class="text-sm text-gray-500 dark:text-gray-400 mb-3">repository settings and hosting.</div>

								<div class="space-y-3">
									{/* Default Branch */}
									<div>
										<label for="branch" class="block text-sm font-bold dark:text-white mb-1">
											DEFAULT BRANCH
										</label>
										<input
											type="text"
											id="branch"
											name="branch"
											value={branch()}
											onInput={(e) => setBranch(e.currentTarget.value)}
											required
											class="w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-900 px-3 py-2 text-sm text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-1 focus:ring-blue-500 focus:border-blue-500 h-[38px]"
										/>
										<p class="text-sm text-gray-500 dark:text-gray-400 mt-1">
											the primary branch where development happens. common choices are "main" or "master".
										</p>
									</div>

									{/* Knot Selection */}
									<div class="pt-2">
										<label class="block text-sm font-bold dark:text-white mb-1">
											SELECT A KNOT
										</label>
										<div class="w-full space-y-1 py-0">
											<Show
												when={!knotsQuery.isLoading}
												fallback={<div class="text-sm text-gray-500 dark:text-gray-400">loading knots...</div>}
											>
												<Show
													when={knotsQuery.data && knotsQuery.data.length > 0}
													fallback={<p class="dark:text-white">no knots available.</p>}
												>
													<For each={knotsQuery.data}>
														{(knot) => (
															<div class="flex items-center leading-tight">
																<input
																	type="radio"
																	name="domain"
																	value={knot}
																	checked={selectedKnot() === knot}
																	onChange={() => setSelectedKnot(knot)}
																	class="mr-2 cursor-pointer"
																	id={`domain-${knot}`}
																	required
																/>
																<label for={`domain-${knot}`} class="dark:text-white lowercase cursor-pointer">
																	{knot}
																</label>
															</div>
														)}
													</For>
												</Show>
											</Show>
										</div>
										<p class="text-sm text-gray-500 dark:text-gray-400 mt-1">
											a knot hosts repository data and handles git operations. you can also{' '}
											<A href="/settings/knots" class="underline">
												register your own knot
											</A>
											.
										</p>
									</div>
								</div>
							</div>
						</div>

						<div class="untangled-repo-form-submit flex justify-end">
							<button
								type="submit"
								disabled={saving() || !selectedKnot()}
								class="btn-create flex items-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed"
							>
								<Show when={saving()} fallback={<BookPlus class="w-4 h-4" />}>
									<LoaderCircle class="w-4 h-4 animate-spin" />
								</Show>
								create repository
							</button>
						</div>
					</form>
				</div>
			</div>
		</Show>
	);
};
