import { useCallback, useEffect, useState } from "react";
import { z } from "zod";
import { useForm, useWatch } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { Form, FormControl, FormField, FormItem, FormMessage } from "./ui/form";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "./ui/select";
import {
	useProjectId,
	useGithubService,
	useGithubRepositories,
	useGithubRepositoriesLoading,
	useGithubRepositoriesError,
	useFetchGithubRepositories,
	useStateStore,
} from "@/lib/state";
import { Alert, AlertDescription } from "./ui/alert";
import { AlertCircle, LoaderCircle, RefreshCw } from "lucide-react";
import { Button } from "./ui/button";
import { v4 as uuidv4 } from "uuid";
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "./ui/dialog";
import { Switch } from "./ui/switch";
import { Label } from "./ui/label";
import { useToast } from "@/hooks/use-toast";
import { serviceAnalyzisSchema, ServiceType, ServiceData } from "config";

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

interface ImportModalProps {
	open: boolean;
	onOpenChange: (open: boolean) => void;
	initialRepositoryId?: number;
}

export function ImportModal({ open, onOpenChange, initialRepositoryId }: ImportModalProps) {
	const { toast } = useToast();
	const store = useStateStore();
	const projectId = useProjectId();
	const githubService = useGithubService();
	const storeRepos = useGithubRepositories();
	const isLoadingRepos = useGithubRepositoriesLoading();
	const repoError = useGithubRepositoriesError();
	const fetchStoreRepositories = useFetchGithubRepositories();

	const [isAnalyzing, setIsAnalyzing] = useState(false);
	const [analysisAttempted, setAnalysisAttempted] = useState(false);
	const [discoveredServices, setDiscoveredServices] = useState<z.infer<typeof serviceAnalyzisSchema>[]>([]);
	const [selectedServices, setSelectedServices] = useState<Record<string, boolean>>({});

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

	const selectedRepoId = useWatch({ control: form.control, name: "repositoryId" });

	useEffect(() => {
		form.reset({ repositoryId: initialRepositoryId });
		setAnalysisAttempted(false);
	}, [initialRepositoryId, form]);

	// Clear analysis results when repository changes
	useEffect(() => {
		setDiscoveredServices([]);
		setSelectedServices({});
		setAnalysisAttempted(false);
	}, [selectedRepoId]);

	const analyze = useCallback(
		async (sshURL: string) => {
			if (!sshURL) return;

			setIsAnalyzing(true);
			try {
				const resp = await fetch(`/api/project/${projectId}/analyze`, {
					method: "POST",
					body: JSON.stringify({
						address: sshURL,
					}),
					headers: {
						"Content-Type": "application/json",
					},
				});
				const servicesResult = z.array(serviceAnalyzisSchema).safeParse(await resp.json());
				if (!servicesResult.success) {
					console.error(servicesResult.error);
					toast({
						variant: "destructive",
						title: "Failed to analyze repository",
					});
					setIsAnalyzing(false);
					return;
				}

				setDiscoveredServices(servicesResult.data);
				const initialSelectedServices: Record<string, boolean> = {};
				servicesResult.data.forEach((service) => {
					initialSelectedServices[service.name] = true;
				});
				setSelectedServices(initialSelectedServices);
			} catch (err) {
				console.error("Analysis failed:", err);
				toast({
					variant: "destructive",
					title: "Failed to analyze repository",
				});
			} finally {
				setIsAnalyzing(false);
			}
		},
		[projectId, toast],
	);

	// Auto-analyze when opened with initialRepositoryId
	useEffect(() => {
		if (open && initialRepositoryId && !isAnalyzing && !discoveredServices.length && !analysisAttempted) {
			const repo = storeRepos.find((r) => r.id === initialRepositoryId);
			if (repo?.ssh_url) {
				setAnalysisAttempted(true);
				analyze(repo.ssh_url);
			}
		}
	}, [open, initialRepositoryId, isAnalyzing, discoveredServices.length, storeRepos, analyze, analysisAttempted]);

	const handleImportServices = () => {
		const repoId = form.getValues("repositoryId");
		if (!repoId) return;

		const repo = storeRepos.find((r) => r.id === repoId);
		if (!repo) return;

		// Check for existing GitHub node for this repository
		const existingGithubNode = store.nodes.find((n) => n.type === "github" && n.data.repository?.id === repo.id);

		const githubNodeId = existingGithubNode?.id || uuidv4();

		// Only create a new GitHub node if one doesn't exist
		if (!existingGithubNode) {
			store.addNode({
				id: githubNodeId,
				type: "github",
				data: {
					label: repo.full_name,
					repository: {
						id: repo.id,
						sshURL: repo.ssh_url,
						fullName: repo.full_name,
					},
					envVars: [],
					ports: [],
					state: null,
				},
			});
		}

		discoveredServices.forEach((service) => {
			if (selectedServices[service.name]) {
				const newNodeData: Omit<ServiceData, "activeField" | "state"> = {
					label: service.name,
					repository: {
						id: repo.id,
						repoNodeId: githubNodeId,
					},
					info: service,
					type: "nodejs:24.0.2" as ServiceType,
					env: [],
					volume: [],
					preBuildCommands: "",
					isChoosingPortToConnect: false,
					envVars: [],
					ports: [],
				};
				const newNodeId = uuidv4();
				store.addNode({
					id: newNodeId,
					type: "app",
					data: newNodeData,
				});
				let edges = store.edges;
				edges = edges.concat({
					id: uuidv4(),
					source: githubNodeId,
					sourceHandle: "repository",
					target: newNodeId,
					targetHandle: "repository",
				});
				store.setEdges(edges);
			}
		});

		onOpenChange(false);
		setDiscoveredServices([]);
		setSelectedServices({});
		form.reset();
	};

	return (
		<Dialog open={open} onOpenChange={onOpenChange}>
			<DialogContent className="sm:max-w-[425px]">
				<DialogHeader>
					<DialogTitle>Import Services</DialogTitle>
					<DialogDescription>Select a repository and analyze it for services.</DialogDescription>
				</DialogHeader>
				<div className="grid gap-4 py-4">
					<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}
												>
													<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()}
																className="cursor-pointer hover:bg-gray-100"
															>
																{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}
													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={!form.getValues("repositoryId") || isAnalyzing || !githubService}
						onClick={() => {
							const repo = storeRepos.find((r) => r.id === form.getValues("repositoryId"));
							if (repo?.ssh_url) {
								analyze(repo.ssh_url);
							}
						}}
					>
						{isAnalyzing && <LoaderCircle className="mr-2 h-4 w-4 animate-spin" />}
						{isAnalyzing ? "Analyzing..." : "Scan for services"}
					</Button>
					{discoveredServices.length > 0 && (
						<div className="grid gap-4">
							<h4 className="font-medium">Discovered Services</h4>
							{discoveredServices.map((service) => (
								<div key={service.name} className="flex flex-col space-y-2 p-2 border rounded-md">
									<div className="flex items-center space-x-2">
										<Switch
											id={service.name}
											checked={selectedServices[service.name]}
											onCheckedChange={(checked: boolean) =>
												setSelectedServices((prev) => ({
													...prev,
													[service.name]: checked,
												}))
											}
										/>
										<Label htmlFor={service.name} className="font-semibold">
											{service.name}
										</Label>
									</div>
									<div className="pl-6 text-sm text-gray-600">
										<p>
											<span className="font-medium">Location:</span> {service.location}
										</p>
										{service.configVars && service.configVars.length > 0 && (
											<div className="mt-1">
												<p className="font-medium">Environment Variables:</p>
												<ul className="list-disc list-inside pl-4">
													{service.configVars.map((envVar) => (
														<li key={envVar.name}>{envVar.name}</li>
													))}
												</ul>
											</div>
										)}
									</div>
								</div>
							))}
						</div>
					)}
				</div>
				<DialogFooter>
					<Button variant="outline" onClick={() => onOpenChange(false)}>
						Cancel
					</Button>
					<Button
						onClick={handleImportServices}
						disabled={!discoveredServices.length || !Object.values(selectedServices).some(Boolean)}
					>
						Import Selected Services
					</Button>
				</DialogFooter>
			</DialogContent>
		</Dialog>
	);
}
