import { NodeRect } from "./node-rect";
import {
	GithubNode,
	nodeIsConnectable,
	nodeLabel,
	useStateStore,
	useGithubService,
	useGithubRepositories,
	useGithubRepositoriesLoading,
	useGithubRepositoriesError,
	useFetchGithubRepositories,
	AppNode,
} from "@/lib/state";
import { useEffect, useMemo, useState } from "react";
import { z } from "zod";
import { DeepPartial, EventType, useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { Form, FormControl, FormField, FormItem, FormMessage } from "./ui/form";
import { Handle, Position } from "@xyflow/react";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "./ui/select";
import { useProjectId } from "@/lib/state";
import { Alert, AlertDescription } from "./ui/alert";
import { AlertCircle, LoaderCircle, RefreshCw } from "lucide-react";
import { Button } from "./ui/button";
import { NodeDetailsProps } from "@/lib/types";
import { ImportModal } from "./import-modal";

export function NodeGithub(node: GithubNode) {
	const { id, selected } = node;
	const isConnectable = useMemo(() => nodeIsConnectable(node, "repository"), [node]);
	return (
		<NodeRect id={id} selected={selected} type={node.type} state={node.data.state}>
			<div style={{ padding: "10px 20px" }}>
				{nodeLabel(node)}
				<Handle
					id="repository"
					type={"source"}
					position={Position.Right}
					isConnectableStart={isConnectable}
					isConnectableEnd={isConnectable}
					isConnectable={isConnectable}
				/>
			</div>
		</NodeRect>
	);
}

const schema = z.object({
	repositoryId: z.number().optional(),
});

export function NodeGithubDetails({ node, disabled }: NodeDetailsProps<GithubNode>) {
	const { id, data } = node;
	const store = useStateStore();
	const projectId = useProjectId();
	const githubService = useGithubService();

	const storeRepos = useGithubRepositories();
	const isLoadingRepos = useGithubRepositoriesLoading();
	const repoError = useGithubRepositoriesError();
	const fetchStoreRepositories = useFetchGithubRepositories();

	const [showImportModal, setShowImportModal] = useState(false);

	const form = useForm<z.infer<typeof schema>>({
		resolver: zodResolver(schema),
		mode: "onChange",
		defaultValues: {
			repositoryId: data.repository?.id,
		},
	});

	useEffect(() => {
		form.reset({ repositoryId: data.repository?.id });
	}, [data.repository?.id, form]);

	useEffect(() => {
		const sub = form.watch(
			(
				value: DeepPartial<z.infer<typeof schema>>,
				{ name, type }: { name?: keyof z.infer<typeof schema> | undefined; type?: EventType | undefined },
			) => {
				if (type !== "change") {
					return;
				}
				switch (name) {
					case "repositoryId":
						if (value.repositoryId) {
							const repo = storeRepos.find((r) => r.id === value.repositoryId);
							if (!repo) {
								return;
							}
							store.setNodes(
								store.nodes.map((n): AppNode => {
									if (n.type === "github" && n.id === id) {
										return {
											...n,
											data: {
												...n.data,
												repository: {
													id: repo.id,
													sshURL: repo.ssh_url,
													fullName: repo.full_name,
												},
											},
										};
									} else if (n.type === "app" && n.data.repository?.repoNodeId === id) {
										return {
											...n,
											data: { ...n.data, repository: { id: repo.id, repoNodeId: id } },
										};
									} else {
										return n;
									}
								}),
							);
						}
						break;
				}
			},
		);
		return () => sub.unsubscribe();
	}, [form, store, id, storeRepos]);

	return (
		<>
			<Form {...form}>
				<form className="space-y-2">
					<FormField
						control={form.control}
						name="repositoryId"
						render={({ field }) => (
							<FormItem>
								<div className="flex items-center gap-2 w-full">
									<div className="flex-grow">
										<Select
											onValueChange={(value) => field.onChange(Number(value))}
											value={field.value?.toString()}
											disabled={isLoadingRepos || !projectId || !githubService || disabled}
										>
											<FormControl>
												<SelectTrigger>
													<SelectValue
														placeholder={
															githubService
																? isLoadingRepos
																	? "Loading..."
																	: storeRepos.length === 0
																		? "No repositories found"
																		: "Select a repository"
																: "GitHub not configured"
														}
													/>
												</SelectTrigger>
											</FormControl>
											<SelectContent>
												{storeRepos.map((repo) => (
													<SelectItem key={repo.id} value={repo.id.toString()}>
														{repo.full_name}
														{repo.description && ` - ${repo.description}`}
													</SelectItem>
												))}
											</SelectContent>
										</Select>
									</div>
									{isLoadingRepos && (
										<Button variant="ghost" size="icon" disabled>
											<LoaderCircle className="h-5 w-5 animate-spin text-muted-foreground" />
										</Button>
									)}
									{!isLoadingRepos && githubService && (
										<Button
											variant="ghost"
											size="icon"
											onClick={fetchStoreRepositories}
											disabled={disabled}
											aria-label="Refresh repositories"
										>
											<RefreshCw className="h-5 w-5 text-muted-foreground" />
										</Button>
									)}
								</div>
								<FormMessage />
								{repoError && <p className="text-sm text-red-500 mt-1">{repoError}</p>}
								{!githubService && (
									<Alert variant="destructive" className="mt-2">
										<AlertCircle className="h-4 w-4" />
										<AlertDescription>
											Please configure Github Personal Access Token in the Integrations tab.
										</AlertDescription>
									</Alert>
								)}
							</FormItem>
						)}
					/>
				</form>
			</Form>
			<Button
				disabled={!data.repository?.sshURL || !githubService || disabled}
				onClick={() => setShowImportModal(true)}
			>
				Scan for services
			</Button>
			<ImportModal
				open={showImportModal}
				onOpenChange={setShowImportModal}
				initialRepositoryId={data.repository?.id}
			/>
		</>
	);
}
