import { Button } from "@/components/ui/button";
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog";
import { getErrorMessage } from "@/lib/store/apis/baseApi";
import { useCompleteOAuthFlowMutation, useLazyGetOAuthConfigStatusQuery } from "@/lib/store/apis/mcpApi";
import { Loader2 } from "lucide-react";
import { useCallback, useEffect, useRef, useState } from "react";

interface OAuth2AuthorizerProps {
	open: boolean;
	onClose: () => void;
	onSuccess: () => void;
	onError: (error: string) => void;
	authorizeUrl: string;
	oauthConfigId: string;
	mcpClientId: string;
	isPerUserOauth?: boolean;
}

export const OAuth2Authorizer: React.FC<OAuth2AuthorizerProps> = ({
	open,
	onClose,
	onSuccess,
	onError,
	authorizeUrl,
	oauthConfigId,
	isPerUserOauth,
}) => {
	const [status, setStatus] = useState<"confirm" | "pending" | "polling" | "success" | "failed">(isPerUserOauth ? "confirm" : "pending");
	const [errorMessage, setErrorMessage] = useState<string | null>(null);
	const popupRef = useRef<Window | null>(null);
	const pollIntervalRef = useRef<NodeJS.Timeout | null>(null);
	const isCompletingRef = useRef(false);

	// RTK Query hooks
	const [getOAuthStatus] = useLazyGetOAuthConfigStatusQuery();
	const [completeOAuth] = useCompleteOAuthFlowMutation();

	// Stop polling
	const stopPolling = useCallback(() => {
		if (pollIntervalRef.current) {
			clearInterval(pollIntervalRef.current);
			pollIntervalRef.current = null;
		}
	}, []);

	// Handle successful OAuth completion
	const handleOAuthComplete = useCallback(async () => {
		// Guard against concurrent calls (race between postMessage and polling)
		if (isCompletingRef.current) return;
		isCompletingRef.current = true;

		// Close popup if still open
		if (popupRef.current && !popupRef.current.closed) {
			popupRef.current.close();
		}

		// Call complete-oauth endpoint using RTK Query mutation
		// Use oauthConfigId instead of mcpClientId for multi-instance support
		try {
			await completeOAuth(oauthConfigId).unwrap();
			setStatus("success");
			onSuccess();
			setTimeout(() => {
				onClose();
			}, 1000);
		} catch (error) {
			const errMsg = getErrorMessage(error);
			setStatus("failed");
			setErrorMessage(errMsg);
			onError(errMsg);
		}
	}, [oauthConfigId, completeOAuth, onSuccess, onClose, onError]);

	// Handle OAuth failure
	const handleOAuthFailed = useCallback(
		(reason: string) => {
			stopPolling();
			if (popupRef.current && !popupRef.current.closed) {
				popupRef.current.close();
			}
			setStatus("failed");
			setErrorMessage(reason);
			onError(reason);
		},
		[stopPolling, onError],
	);

	// Check OAuth status (called by postMessage or polling)
	const checkOAuthStatus = useCallback(async () => {
		try {
			const result = await getOAuthStatus(oauthConfigId).unwrap();

			if (result.status === "authorized") {
				stopPolling();
				await handleOAuthComplete();
			} else if (result.status === "failed" || result.status === "expired") {
				handleOAuthFailed(`Authorization ${result.status}`);
			}
		} catch (error) {
			console.error("Error checking OAuth status:", error);
		}
	}, [oauthConfigId, getOAuthStatus, stopPolling, handleOAuthComplete, handleOAuthFailed]);

	// Poll OAuth status
	const startPolling = useCallback(() => {
		// Clear any existing interval
		if (pollIntervalRef.current) {
			clearInterval(pollIntervalRef.current);
		}

		pollIntervalRef.current = setInterval(async () => {
			// Check if popup is still open
			if (popupRef.current && popupRef.current.closed) {
				// Popup closed - check status before assuming cancellation
				// (OAuth callback page closes the popup after success)
				try {
					const result = await getOAuthStatus(oauthConfigId).unwrap();
					if (result.status === "authorized") {
						stopPolling();
						await handleOAuthComplete();
					} else if (result.status === "failed" || result.status === "expired") {
						stopPolling();
						handleOAuthFailed("Authorization failed");
					}
					// pending or other non-terminal: let polling continue
				} catch {
					// transient fetch error: let polling continue
				}
				return;
			}

			await checkOAuthStatus();
		}, 2000); // Poll every 2 seconds
	}, [checkOAuthStatus, handleOAuthFailed]);

	// Open popup and start polling
	const openPopup = useCallback(() => {
		// Reset completion guard for each fresh OAuth attempt
		isCompletingRef.current = false;

		// Close any existing popup
		if (popupRef.current && !popupRef.current.closed) {
			popupRef.current.close();
		}

		// Open OAuth popup
		const width = 600;
		const height = 700;
		const left = window.screen.width / 2 - width / 2;
		const top = window.screen.height / 2 - height / 2;

		popupRef.current = window.open(
			authorizeUrl,
			"oauth_popup",
			`width=${width},height=${height},left=${left},top=${top},resizable=yes,scrollbars=yes`,
		);

		setStatus("polling");

		// Start polling OAuth status
		startPolling();
	}, [authorizeUrl, startPolling]);

	// Listen for postMessage from OAuth callback popup
	useEffect(() => {
		const handleMessage = (event: MessageEvent) => {
			// Verify message is from OAuth callback
			if (event.data?.type === "oauth_success") {
				// Trigger immediate status check; stopPolling is called inside
				// checkOAuthStatus only after a confirmed terminal state, so
				// transient fetch errors still allow polling to continue.
				checkOAuthStatus();
			}
		};

		window.addEventListener("message", handleMessage);
		return () => {
			window.removeEventListener("message", handleMessage);
		};
	}, [checkOAuthStatus]);

	// Open popup when dialog opens (skip if waiting for user confirmation)
	useEffect(() => {
		if (open && status === "pending") {
			openPopup();
		}
	}, [open, status, openPopup]);

	// Handle user confirming per-user OAuth test
	const handleConfirmPerUserOAuth = () => {
		setStatus("pending");
		openPopup();
	};

	// Cleanup on unmount
	useEffect(() => {
		return () => {
			stopPolling();
			if (popupRef.current && !popupRef.current.closed) {
				popupRef.current.close();
			}
		};
	}, [stopPolling]);

	const handleRetry = () => {
		setErrorMessage(null);
		isCompletingRef.current = false;
		if (isPerUserOauth) {
			setStatus("confirm");
		} else {
			setStatus("pending");
			openPopup();
		}
	};

	const handleCancel = () => {
		stopPolling();
		isCompletingRef.current = false;
		if (popupRef.current && !popupRef.current.closed) {
			popupRef.current.close();
		}
		onClose();
	};

	return (
		<Dialog open={open}>
			<DialogContent className="sm:max-w-md" onPointerDownOutside={(e) => e.preventDefault()} onEscapeKeyDown={(e) => e.preventDefault()}>
				<DialogHeader>
					<DialogTitle>{status === "confirm" ? "Test OAuth Configuration" : "OAuth Authorization"}</DialogTitle>
					<DialogDescription>
						{status === "confirm" && "A one-time login is needed to verify your OAuth setup."}
						{status === "pending" && "Opening authorization window..."}
						{status === "polling" && "Waiting for authorization..."}
						{status === "success" && "Authorization successful!"}
						{status === "failed" && "Authorization failed"}
					</DialogDescription>
				</DialogHeader>

				<div className="flex flex-col items-center justify-center space-y-4">
					{status === "confirm" && (
						<>
							<div className="text-muted-foreground space-y-3 text-sm">
								<p>
									To set up this MCP server, we need to verify that your OAuth configuration is correct and discover the available tools.
								</p>
								<p>
									You will be asked to log in to the OAuth provider. This is a <strong>one-time test</strong> to confirm the setup works.
									Your credentials will <strong>not</strong> be stored or used for any other purpose.
								</p>
								<p>Once verified, each user will authenticate individually when they use this MCP server.</p>
							</div>
							<div className="flex w-full justify-end space-x-2">
								<Button onClick={handleCancel} variant="outline" data-testid="per-user-oauth-cancel">
									Cancel
								</Button>
								<Button onClick={handleConfirmPerUserOAuth} data-testid="per-user-oauth-confirm">
									Continue with Test Login
								</Button>
							</div>
						</>
					)}

					{status === "polling" && (
						<>
							<Loader2 className="text-secondary-foreground h-4 w-4 animate-spin" />
							<p className="text-muted-foreground text-sm">Please complete authorization in the popup window</p>
						</>
					)}

					{status === "success" && (
						<>
							<div className="flex h-12 w-12 items-center justify-center rounded-full bg-green-100">
								<svg className="h-6 w-6 text-green-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
									<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
								</svg>
							</div>
							<p className="text-sm text-green-600">MCP server connected successfully!</p>
						</>
					)}

					{status === "failed" && (
						<>
							<div className="flex h-12 w-12 items-center justify-center rounded-full bg-red-100">
								<svg className="h-6 w-6 text-red-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
									<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
								</svg>
							</div>
							<p className="text-sm text-red-600">{errorMessage || "An error occurred"}</p>
							<Button onClick={handleRetry} variant="outline">
								Retry
							</Button>
						</>
					)}
				</div>

				{status === "polling" && (
					<div className="flex justify-end space-x-2">
						<Button onClick={handleCancel} variant="outline">
							Cancel
						</Button>
					</div>
				)}
			</DialogContent>
		</Dialog>
	);
};