/**
 * Device Authorization Page
 *
 * Standalone page where users enter the code displayed by `emdash login`
 * to authorize a CLI or agent to access their account.
 *
 * Flow:
 * 1. User runs `emdash login` → sees a code like ABCD-1234
 * 2. User opens this page in their browser (already logged in)
 * 3. User enters the code → clicks Authorize
 * 4. CLI receives tokens and saves them
 */

import { Button, Input } from "@cloudflare/kumo";
import { useQuery } from "@tanstack/react-query";
import * as React from "react";

import { apiFetch, API_BASE, parseApiResponse } from "../lib/api";

// ============================================================================
// Types
// ============================================================================

interface UserInfo {
	id: string;
	email: string;
	name: string | null;
	role: number;
}

type PageState = "input" | "submitting" | "success" | "denied" | "error";

// ============================================================================
// Constants
// ============================================================================

const ROLE_NAMES: Record<number, string> = {
	10: "Subscriber",
	20: "Contributor",
	30: "Author",
	40: "Editor",
	50: "Admin",
};

const DEVICE_CODE_INVALID_CHARS_REGEX = /[^A-Z0-9-]/g;
const DEVICE_CODE_HYPHEN_REGEX = /-/g;

// ============================================================================
// Component
// ============================================================================

export function DeviceAuthorizePage() {
	const [code, setCode] = React.useState("");
	const [pageState, setPageState] = React.useState<PageState>("input");
	const [errorMessage, setErrorMessage] = React.useState("");

	// Check if user is logged in
	const {
		data: user,
		isLoading,
		error: authError,
	} = useQuery<UserInfo>({
		queryKey: ["auth-me"],
		queryFn: async () => {
			const res = await apiFetch(`${API_BASE}/auth/me`);
			return parseApiResponse<UserInfo>(res, "Not authenticated");
		},
		retry: false,
	});

	// Pre-populate from URL query param (?code=ABCD-1234)
	React.useEffect(() => {
		const params = new URLSearchParams(window.location.search);
		const urlCode = params.get("code");
		if (urlCode) {
			setCode(urlCode);
		}
	}, []);

	// Not authenticated — redirect to login
	React.useEffect(() => {
		if (!isLoading && (authError || !user)) {
			const returnUrl = encodeURIComponent(window.location.pathname + window.location.search);
			window.location.href = `/_emdash/admin/login?redirect=${returnUrl}`;
		}
	}, [isLoading, authError, user]);

	async function handleSubmit(e: React.FormEvent) {
		e.preventDefault();

		const trimmed = code.trim();
		if (!trimmed) return;

		setPageState("submitting");
		setErrorMessage("");

		try {
			const res = await apiFetch(`${API_BASE}/oauth/device/authorize`, {
				method: "POST",
				headers: { "Content-Type": "application/json" },
				body: JSON.stringify({ user_code: trimmed, action: "approve" }),
			});

			const data = await parseApiResponse<{ authorized: boolean }>(res, "Authorization failed");
			setPageState(data.authorized ? "success" : "denied");
		} catch (err) {
			setErrorMessage(err instanceof Error ? err.message : "Network error");
			setPageState("error");
		}
	}

	async function handleDeny(e: React.FormEvent) {
		e.preventDefault();

		const trimmed = code.trim();
		if (!trimmed) return;

		setPageState("submitting");

		try {
			await apiFetch(`${API_BASE}/oauth/device/authorize`, {
				method: "POST",
				headers: { "Content-Type": "application/json" },
				body: JSON.stringify({ user_code: trimmed, action: "deny" }),
			});
			setPageState("denied");
		} catch {
			setPageState("denied");
		}
	}

	// Format code as user types (insert hyphen after 4 chars)
	function handleCodeChange(e: React.ChangeEvent<HTMLInputElement>) {
		let value = e.target.value.toUpperCase().replace(DEVICE_CODE_INVALID_CHARS_REGEX, "");

		// Auto-insert hyphen after 4 chars if not already present
		if (value.length === 4 && !value.includes("-")) {
			value = value + "-";
		}

		// Limit to 9 chars (XXXX-XXXX)
		if (value.length > 9) {
			value = value.slice(0, 9);
		}

		setCode(value);
	}

	if (isLoading) {
		return (
			<PageWrapper>
				<p className="text-kumo-subtle text-sm">Checking authentication...</p>
			</PageWrapper>
		);
	}

	if (!user) {
		return (
			<PageWrapper>
				<p className="text-kumo-subtle text-sm">Redirecting to login...</p>
			</PageWrapper>
		);
	}

	return (
		<PageWrapper>
			<div className="w-full max-w-sm">
				{/* Header */}
				<div className="text-center mb-8">
					<div className="inline-flex items-center justify-center w-12 h-12 rounded-xl bg-kumo-brand/10 mb-4">
						<TerminalIcon className="w-6 h-6 text-kumo-brand" />
					</div>
					<h1 className="text-xl font-semibold tracking-tight">Authorize Device</h1>
					<p className="text-kumo-subtle text-sm mt-1.5">Enter the code from your terminal</p>
				</div>

				{/* Success state */}
				{pageState === "success" && (
					<div className="rounded-lg border border-green-200 bg-green-50 dark:border-green-900 dark:bg-green-950/50 p-6 text-center">
						<div className="inline-flex items-center justify-center w-10 h-10 rounded-full bg-green-100 dark:bg-green-900/50 mb-3">
							<CheckIcon className="w-5 h-5 text-green-600 dark:text-green-400" />
						</div>
						<h2 className="font-medium text-green-900 dark:text-green-100">Device authorized</h2>
						<p className="text-sm text-green-700 dark:text-green-300 mt-1">
							You can close this page and return to your terminal.
						</p>
						<p className="text-xs text-kumo-subtle mt-3">Signed in as {user.email}</p>
					</div>
				)}

				{/* Denied state */}
				{pageState === "denied" && (
					<div className="rounded-lg border border-kumo-line p-6 text-center">
						<h2 className="font-medium">Authorization denied</h2>
						<p className="text-sm text-kumo-subtle mt-1">The device will not be granted access.</p>
						<Button
							className="mt-4"
							variant="outline"
							onClick={() => {
								setPageState("input");
								setCode("");
							}}
						>
							Try another code
						</Button>
					</div>
				)}

				{/* Input / Error state */}
				{(pageState === "input" || pageState === "submitting" || pageState === "error") && (
					<form onSubmit={handleSubmit}>
						<div className="rounded-lg border border-kumo-line bg-kumo-base p-6">
							{/* User badge */}
							<div className="flex items-center gap-2 mb-5 pb-4 border-b border-kumo-line">
								<div className="w-8 h-8 rounded-full bg-kumo-tint flex items-center justify-center text-xs font-medium">
									{(user.name || user.email).charAt(0).toUpperCase()}
								</div>
								<div className="min-w-0">
									<p className="text-sm font-medium truncate">{user.name || user.email}</p>
									<p className="text-xs text-kumo-subtle">{ROLE_NAMES[user.role] || "User"}</p>
								</div>
							</div>

							{/* Code input */}
							<label className="block text-sm font-medium mb-2" htmlFor="user-code">
								Device code
							</label>
							<Input
								id="user-code"
								type="text"
								value={code}
								onChange={handleCodeChange}
								placeholder="XXXX-XXXX"
								className="text-center text-lg font-mono tracking-widest"
								autoFocus
								autoComplete="off"
								spellCheck={false}
								disabled={pageState === "submitting"}
							/>

							{/* Error message */}
							{pageState === "error" && errorMessage && (
								<p className="text-sm text-kumo-danger mt-2">{errorMessage}</p>
							)}

							{/* Actions */}
							<div className="flex gap-2 mt-4">
								<Button
									type="submit"
									className="flex-1"
									disabled={
										code.replace(DEVICE_CODE_HYPHEN_REGEX, "").length < 8 ||
										pageState === "submitting"
									}
								>
									{pageState === "submitting" ? "Authorizing..." : "Authorize"}
								</Button>
								<Button
									type="button"
									variant="outline"
									onClick={handleDeny}
									disabled={
										code.replace(DEVICE_CODE_HYPHEN_REGEX, "").length < 8 ||
										pageState === "submitting"
									}
								>
									Deny
								</Button>
							</div>
						</div>

						<p className="text-xs text-kumo-subtle text-center mt-4">
							This will grant CLI access with your permissions.
							<br />
							Only authorize codes you recognize.
						</p>
					</form>
				)}
			</div>
		</PageWrapper>
	);
}

// ============================================================================
// Layout wrapper
// ============================================================================

function PageWrapper({ children }: { children: React.ReactNode }) {
	return (
		<div className="min-h-screen flex items-center justify-center bg-kumo-base p-4">
			<div className="w-full max-w-sm">{children}</div>
		</div>
	);
}

// ============================================================================
// Icons (inline SVG to avoid dependency on icon library for this simple page)
// ============================================================================

function TerminalIcon({ className }: { className?: string }) {
	return (
		<svg
			className={className}
			viewBox="0 0 24 24"
			fill="none"
			stroke="currentColor"
			strokeWidth={2}
			strokeLinecap="round"
			strokeLinejoin="round"
		>
			<polyline points="4 17 10 11 4 5" />
			<line x1="12" y1="19" x2="20" y2="19" />
		</svg>
	);
}

function CheckIcon({ className }: { className?: string }) {
	return (
		<svg
			className={className}
			viewBox="0 0 24 24"
			fill="none"
			stroke="currentColor"
			strokeWidth={2}
			strokeLinecap="round"
			strokeLinejoin="round"
		>
			<polyline points="20 6 9 17 4 12" />
		</svg>
	);
}
