import { Badge } from '@public/components/ui/badge'
import { Button } from '@public/components/ui/button'
import { Checkbox } from '@public/components/ui/checkbox'
import {
	Dialog,
	DialogContent,
	DialogDescription,
	DialogFooter,
	DialogHeader,
	DialogTitle,
} from '@public/components/ui/dialog'
import { Input } from '@public/components/ui/input'
import { Label } from '@public/components/ui/label'
import { RadioGroup, RadioGroupItem } from '@public/components/ui/radio-group'
import { SkeletonShimmer } from '@public/components/ui/skeleton'
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@public/components/ui/tabs'
import Layout from '@public/layouts'
import { Loader2, LogOut, Trash2 } from 'lucide-react'
import { type ChangeEvent, type KeyboardEvent as ReactKeyboardEvent, useCallback, useEffect, useState } from 'react'
import { createRoot } from 'react-dom/client'
import { BrowserRouter, Route, Routes } from 'react-router-dom'
import { useDomainData } from './hooks/useDomainData'
import { useSecretData } from './hooks/useSecretData'
import { type SiteWithDomains, useSiteData } from './hooks/useSiteData'
import { useUserInfo } from './hooks/useUserInfo'
import { useWebhookData } from './hooks/useWebhookData'
import { CLITab } from './tabs/CLITab'
import { DomainsTab } from './tabs/DomainsTab'
import { SitesTab } from './tabs/SitesTab'
import { UploadTab } from './tabs/UploadTab'
import { WebhooksTab } from './tabs/WebhooksTab'

function Dashboard() {
	const dashboardInset = '2.8rem'
	const dashboardMaxWidth = '72rem'
	const mascotStyle = {
		left: `calc((100vw - min(${dashboardMaxWidth}, 100vw)) / 2 + ${dashboardInset})`,
		width: 'clamp(14rem, 19vw, 17rem)',
	} as const

	// Use custom hooks
	const { userInfo, loading, isAuthenticated, fetchUserInfo } = useUserInfo()
	const { sites, sitesLoading, fetchSites, deleteSite } = useSiteData()
	const {
		webhooks,
		webhooksLoading,
		fetchWebhooks,
		eventLogs,
		eventLogsLoading,
		fetchEventLogs,
		isCreating,
		createWebhook,
		deleteWebhook,
	} = useWebhookData()
	const { secrets, secretsLoading, isCreatingSecret, fetchSecrets, createSecret, deleteSecret, rotateSecret } =
		useSecretData()

	const {
		wispDomains,
		customDomains,
		domainsLoading,
		verificationStatus,
		fetchDomains,
		addCustomDomain,
		verifyDomain,
		deleteCustomDomain,
		mapWispDomain,
		deleteWispDomain,
		mapCustomDomain,
		claimWispDomain,
		checkWispAvailability,
	} = useDomainData()

	// Site configuration modal state (shared across components)
	const [configuringSite, setConfiguringSite] = useState<SiteWithDomains | null>(null)
	const [selectedDomains, setSelectedDomains] = useState<Set<string>>(new Set())
	const [isSavingConfig, setIsSavingConfig] = useState(false)
	const [isDeletingSite, setIsDeletingSite] = useState(false)
	const [deleteConfirmSite, setDeleteConfirmSite] = useState<SiteWithDomains | null>(null)

	// Site settings state
	type RoutingMode = 'default' | 'spa' | 'directory' | 'custom404'
	const [routingMode, setRoutingMode] = useState<RoutingMode>('default')
	const [spaFile, setSpaFile] = useState('index.html')
	const [custom404File, setCustom404File] = useState('404.html')
	const [indexFiles, setIndexFiles] = useState<string[]>(['index.html'])
	const [newIndexFile, setNewIndexFile] = useState('')
	const [cleanUrls, setCleanUrls] = useState(false)
	const [corsEnabled, setCorsEnabled] = useState(false)
	const [corsOrigin, setCorsOrigin] = useState('*')

	// Tab state
	const [activeTab, setActiveTab] = useState('sites')

	// Fetch initial data on mount — empty deps intentional, run once
	// biome-ignore lint/correctness/useExhaustiveDependencies: initial mount fetch
	useEffect(() => {
		fetchUserInfo()
		fetchSites()
		fetchDomains()
		fetchWebhooks()
		fetchEventLogs()
		fetchSecrets()
	}, [])

	// Redirect to home if not authenticated
	useEffect(() => {
		if (isAuthenticated === false) {
			window.location.href = '/'
		}
	}, [isAuthenticated])

	// Keyboard navigation for tabs
	useEffect(() => {
		const handleKeyDown = (e: KeyboardEvent) => {
			// Don't handle keyboard shortcuts if:
			// - A modal/dialog is open
			// - User is typing in an input/textarea
			const target = e.target as HTMLElement
			const isTyping = target.tagName === 'INPUT' || target.tagName === 'TEXTAREA'
			const isModalOpen = configuringSite !== null || document.querySelector('[role="dialog"]') !== null

			if (isModalOpen || isTyping) {
				return
			}

			// Handle tab navigation with arrow keys (Left/Right only)
			if (e.key === 'ArrowLeft' || e.key === 'ArrowRight') {
				const tabs = ['sites', 'domains', 'upload', 'webhooks', 'cli']
				const currentIndex = tabs.indexOf(activeTab)

				if (e.key === 'ArrowLeft' && currentIndex > 0) {
					e.preventDefault()
					setActiveTab(tabs[currentIndex - 1])
				} else if (e.key === 'ArrowRight' && currentIndex < tabs.length - 1) {
					e.preventDefault()
					setActiveTab(tabs[currentIndex + 1])
				}
			}
		}

		window.addEventListener('keydown', handleKeyDown)
		return () => window.removeEventListener('keydown', handleKeyDown)
	}, [activeTab, configuringSite])

	// Handle site configuration modal
	const handleConfigureSite = useCallback(async (site: SiteWithDomains) => {
		setConfiguringSite(site)

		// Build set of currently mapped domains
		const mappedDomains = new Set<string>()

		if (site.domains) {
			site.domains.forEach((domainInfo) => {
				if (domainInfo.type === 'wisp') {
					// For wisp domains, use the domain itself as the identifier
					mappedDomains.add(`wisp:${domainInfo.domain}`)
				} else if (domainInfo.id) {
					mappedDomains.add(domainInfo.id)
				}
			})
		}

		setSelectedDomains(mappedDomains)

		// Fetch and populate settings for this site
		try {
			const response = await fetch(`/api/site/${site.rkey}/settings`, {
				credentials: 'include',
			})
			if (response.ok) {
				const settings = await response.json()

				// Determine routing mode based on settings
				if (settings.spaMode) {
					setRoutingMode('spa')
					setSpaFile(settings.spaMode)
				} else if (settings.directoryListing) {
					setRoutingMode('directory')
				} else if (settings.custom404) {
					setRoutingMode('custom404')
					setCustom404File(settings.custom404)
				} else {
					setRoutingMode('default')
				}

				// Set other settings
				setIndexFiles(settings.indexFiles || ['index.html'])
				setCleanUrls(settings.cleanUrls || false)

				// Check for CORS headers
				const corsHeader = settings.headers?.find((h: any) => h.name === 'Access-Control-Allow-Origin')
				if (corsHeader) {
					setCorsEnabled(true)
					setCorsOrigin(corsHeader.value)
				} else {
					setCorsEnabled(false)
					setCorsOrigin('*')
				}
			} else {
				// Reset to defaults if no settings found
				setRoutingMode('default')
				setSpaFile('index.html')
				setCustom404File('404.html')
				setIndexFiles(['index.html'])
				setCleanUrls(false)
				setCorsEnabled(false)
				setCorsOrigin('*')
			}
		} catch (err) {
			console.error('Failed to fetch settings:', err)
			// Use defaults on error
			setRoutingMode('default')
			setSpaFile('index.html')
			setCustom404File('404.html')
			setIndexFiles(['index.html'])
			setCleanUrls(false)
			setCorsEnabled(false)
			setCorsOrigin('*')
		}
	}, [])

	const handleSaveSiteConfig = async () => {
		if (!configuringSite) return

		setIsSavingConfig(true)
		try {
			// Handle wisp domain mappings
			const selectedWispDomainIds = Array.from(selectedDomains).filter((id) => id.startsWith('wisp:'))
			const selectedWispDomains = selectedWispDomainIds.map((id) => id.replace('wisp:', ''))

			// Get currently mapped wisp domains
			const currentlyMappedWispDomains = wispDomains.filter((d) => d.rkey === configuringSite.rkey)

			// Unmap wisp domains that are no longer selected
			for (const domain of currentlyMappedWispDomains) {
				if (!selectedWispDomains.includes(domain.domain)) {
					await mapWispDomain(domain.domain, null)
				}
			}

			// Map newly selected wisp domains
			for (const domainName of selectedWispDomains) {
				const isAlreadyMapped = currentlyMappedWispDomains.some((d) => d.domain === domainName)
				if (!isAlreadyMapped) {
					await mapWispDomain(domainName, configuringSite.rkey)
				}
			}

			// Handle custom domain mappings
			const selectedCustomDomainIds = Array.from(selectedDomains).filter((id) => !id.startsWith('wisp:'))
			const currentlyMappedCustomDomains = customDomains.filter((d) => d.rkey === configuringSite.rkey)

			// Unmap domains that are no longer selected
			for (const domain of currentlyMappedCustomDomains) {
				if (!selectedCustomDomainIds.includes(domain.id)) {
					await mapCustomDomain(domain.id, null)
				}
			}

			// Map newly selected domains
			for (const domainId of selectedCustomDomainIds) {
				const isAlreadyMapped = currentlyMappedCustomDomains.some((d) => d.id === domainId)
				if (!isAlreadyMapped) {
					await mapCustomDomain(domainId, configuringSite.rkey)
				}
			}

			// Save site settings
			const settings: any = {
				cleanUrls,
				indexFiles: indexFiles.filter((f) => f.trim() !== ''),
			}

			// Set routing mode based on selection
			if (routingMode === 'spa') {
				settings.spaMode = spaFile
			} else if (routingMode === 'directory') {
				settings.directoryListing = true
			} else if (routingMode === 'custom404') {
				settings.custom404 = custom404File
			}

			// Add CORS header if enabled
			if (corsEnabled) {
				settings.headers = [
					{
						name: 'Access-Control-Allow-Origin',
						value: corsOrigin,
					},
				]
			}

			const settingsResponse = await fetch(`/api/site/${configuringSite.rkey}/settings`, {
				method: 'POST',
				headers: {
					'Content-Type': 'application/json',
				},
				credentials: 'include',
				body: JSON.stringify(settings),
			})

			if (!settingsResponse.ok) {
				const error = await settingsResponse.json()
				throw new Error(error.error || 'Failed to save settings')
			}

			// Refresh both domains and sites to get updated mappings
			await fetchDomains()
			await fetchSites()
			setConfiguringSite(null)
		} catch (err) {
			console.error('Save config error:', err)
			alert(`Failed to save configuration: ${err instanceof Error ? err.message : 'Unknown error'}`)
		} finally {
			setIsSavingConfig(false)
		}
	}

	const handleDeleteConfirmSite = useCallback((site: SiteWithDomains) => {
		setDeleteConfirmSite(site)
	}, [])

	const handleDeleteSite = async () => {
		const site = configuringSite || deleteConfirmSite
		if (!site) return

		setIsDeletingSite(true)
		// Private sites are deleted through their own endpoint; they have no PDS record.
		const success = await deleteSite(site.isPrivate ? (site.siteId ?? site.rkey) : site.rkey, site.isPrivate)
		if (success) {
			// Refresh domains in case this site was mapped
			await fetchDomains()
			setConfiguringSite(null)
			setDeleteConfirmSite(null)
		}
		setIsDeletingSite(false)
	}

	const handleUploadComplete = useCallback(async () => {
		await fetchSites()
	}, [fetchSites])

	const handleLogout = async () => {
		try {
			const response = await fetch('/api/auth/logout', {
				method: 'POST',
				credentials: 'include',
			})
			const result = await response.json()
			if (result.success) {
				// Redirect to home page after successful logout
				window.location.href = '/'
			} else {
				alert(`Logout failed: ${result.error || 'Unknown error'}`)
			}
		} catch (err) {
			alert(`Logout failed: ${err instanceof Error ? err.message : 'Unknown error'}`)
		}
	}

	if (loading) {
		return (
			<div className="w-full min-h-screen bg-background font-mono">
				{/* Header Skeleton */}
				<header className="w-full border-b border-border/40 bg-background sticky top-0 z-50">
					<div className="max-w-6xl w-full mx-auto px-6 py-6 flex items-start justify-between">
						<div className="space-y-2">
							<SkeletonShimmer className="h-8 w-48" />
							<SkeletonShimmer className="h-4 w-64" />
						</div>
						<div className="flex items-center gap-3">
							<SkeletonShimmer className="h-4 w-32" />
							<SkeletonShimmer className="h-8 w-8 rounded" />
						</div>
					</div>
				</header>

				<div className="container mx-auto px-6 py-6 max-w-6xl w-full">
					{/* Keyboard shortcuts skeleton */}
					<div className="mb-6">
						<SkeletonShimmer className="h-6 w-96" />
					</div>

					{/* Tabs Skeleton */}
					<div className="space-y-6 w-full">
						<div className="grid w-full grid-cols-5 border-b border-border/50">
							{['a', 'b', 'c', 'd', 'e'].map((id) => (
								<SkeletonShimmer key={id} className="h-10 w-full" />
							))}
						</div>

						{/* Content Skeleton */}
						<div className="space-y-2">
							<SkeletonShimmer className="h-6 w-full mb-4" />
							{['a', 'b', 'c'].map((id) => (
								<div key={id} className="border border-border/30 p-4">
									<SkeletonShimmer className="h-5 w-full" />
								</div>
							))}
						</div>
					</div>
				</div>
			</div>
		)
	}

	return (
		<div className="relative isolate w-full h-screen bg-background flex flex-col font-mono overflow-hidden">
			{/* Header */}
			<header className="relative z-10 w-full border-b border-border/40 bg-background flex-shrink-0">
				<div className="max-w-6xl w-full mx-auto px-6 py-6 flex items-start justify-between">
					<div className="space-y-2">
						<h1 className="text-3xl font-bold tracking-tight">Dashboard</h1>
						<p className="text-sm text-muted-foreground">Manage your sites and domains</p>
					</div>
					<div className="flex items-center gap-3">
						<div className="flex items-center gap-2">
							<span className="text-sm text-muted-foreground">{userInfo?.handle || 'Loading...'}</span>
							{userInfo?.isSupporter && (
								<Badge variant="default" className="text-xs">
									Supporter
								</Badge>
							)}
						</div>
						<Button variant="ghost" size="sm" onClick={handleLogout} className="h-8 px-2">
							<LogOut className="w-4 h-4" />
						</Button>
					</div>
				</div>
			</header>

			{/* Main content area - fills remaining space */}
			<div className="relative z-10 flex-1 overflow-hidden flex flex-col">
				<div className="container relative mx-auto px-6 py-6 max-w-6xl w-full flex flex-col h-full overflow-visible">
					{/* Keyboard shortcuts hint */}
					<div className="mb-4 flex items-center gap-4 text-xs text-muted-foreground flex-shrink-0">
						<div className="flex items-center gap-2">
							<kbd className="px-2 py-1 bg-muted/50 rounded border border-border/50">←</kbd>
							<kbd className="px-2 py-1 bg-muted/50 rounded border border-border/50">→</kbd>
							<span>switch tabs</span>
						</div>
						<span>•</span>
						<div className="flex items-center gap-2">
							<kbd className="px-2 py-1 bg-muted/50 rounded border border-border/50">↑</kbd>
							<kbd className="px-2 py-1 bg-muted/50 rounded border border-border/50">↓</kbd>
							<span>navigate items</span>
						</div>
					</div>

					<Tabs
						value={activeTab}
						onValueChange={setActiveTab}
						className="relative z-10 flex flex-col flex-1 overflow-hidden"
					>
						<TabsList className="grid w-full grid-cols-5 bg-card border-b border-border/50 rounded-none h-auto p-0 flex-shrink-0">
							<TabsTrigger
								value="sites"
								className="rounded-none border-b-2 border-transparent text-muted-foreground hover:text-foreground hover:bg-muted/50 data-[state=active]:border-accent data-[state=active]:bg-transparent data-[state=active]:text-foreground data-[state=active]:shadow-none py-3"
							>
								Sites
							</TabsTrigger>
							<TabsTrigger
								value="domains"
								className="rounded-none border-b-2 border-transparent text-muted-foreground hover:text-foreground hover:bg-muted/50 data-[state=active]:border-accent data-[state=active]:bg-transparent data-[state=active]:text-foreground data-[state=active]:shadow-none py-3"
							>
								Domains
							</TabsTrigger>
							<TabsTrigger
								value="upload"
								className="rounded-none border-b-2 border-transparent text-muted-foreground hover:text-foreground hover:bg-muted/50 data-[state=active]:border-accent data-[state=active]:bg-transparent data-[state=active]:text-foreground data-[state=active]:shadow-none py-3"
							>
								Upload
							</TabsTrigger>
							<TabsTrigger
								value="webhooks"
								className="rounded-none border-b-2 border-transparent text-muted-foreground hover:text-foreground hover:bg-muted/50 data-[state=active]:border-accent data-[state=active]:bg-transparent data-[state=active]:text-foreground data-[state=active]:shadow-none py-3"
							>
								Webhooks
							</TabsTrigger>
							<TabsTrigger
								value="cli"
								className="rounded-none border-b-2 border-transparent text-muted-foreground hover:text-foreground hover:bg-muted/50 data-[state=active]:border-accent data-[state=active]:bg-transparent data-[state=active]:text-foreground data-[state=active]:shadow-none py-3"
							>
								Cli
							</TabsTrigger>
						</TabsList>

						{/* Tab content — all tabs stay in the layout tree via absolute positioning to avoid
						    the display:none→visible reflow cost. Inactive tabs use visibility:hidden instead. */}
						<div className="flex-1 relative mt-4 overflow-hidden">
							<TabsContent
								value="sites"
								className="absolute inset-0 overflow-hidden content-visibility-auto data-[state=inactive]:invisible data-[state=inactive]:pointer-events-none"
							>
								<SitesTab
									sites={sites}
									sitesLoading={sitesLoading}
									userInfo={userInfo}
									onConfigureSite={handleConfigureSite}
									onDeleteSite={handleDeleteConfirmSite}
								/>
							</TabsContent>

							<TabsContent
								value="domains"
								className="absolute inset-0 overflow-hidden content-visibility-auto data-[state=inactive]:invisible data-[state=inactive]:pointer-events-none"
							>
								<DomainsTab
									wispDomains={wispDomains}
									customDomains={customDomains}
									domainsLoading={domainsLoading}
									verificationStatus={verificationStatus}
									userInfo={userInfo}
									onAddCustomDomain={addCustomDomain}
									onVerifyDomain={verifyDomain}
									onDeleteCustomDomain={deleteCustomDomain}
									onDeleteWispDomain={deleteWispDomain}
									onClaimWispDomain={claimWispDomain}
									onCheckWispAvailability={checkWispAvailability}
								/>
							</TabsContent>

							<TabsContent
								value="upload"
								className="absolute inset-0 overflow-hidden content-visibility-auto data-[state=inactive]:invisible data-[state=inactive]:pointer-events-none"
							>
								<UploadTab sites={sites} sitesLoading={sitesLoading} onUploadComplete={handleUploadComplete} />
							</TabsContent>

							<TabsContent
								value="webhooks"
								className="absolute inset-0 overflow-hidden content-visibility-auto data-[state=inactive]:invisible data-[state=inactive]:pointer-events-none"
							>
								<WebhooksTab
									webhooks={webhooks}
									webhooksLoading={webhooksLoading}
									eventLogs={eventLogs}
									eventLogsLoading={eventLogsLoading}
									isCreating={isCreating}
									userDid={userInfo?.did}
									secrets={secrets}
									secretsLoading={secretsLoading}
									isCreatingSecret={isCreatingSecret}
									onCreateWebhook={createWebhook}
									onDeleteWebhook={deleteWebhook}
									onRefreshEvents={fetchEventLogs}
									onCreateSecret={createSecret}
									onDeleteSecret={deleteSecret}
									onRotateSecret={rotateSecret}
								/>
							</TabsContent>

							<TabsContent
								value="cli"
								className="absolute inset-0 overflow-hidden content-visibility-auto data-[state=inactive]:invisible data-[state=inactive]:pointer-events-none"
							>
								<CLITab />
							</TabsContent>
						</div>
					</Tabs>
				</div>
			</div>

			<div className="pointer-events-none absolute bottom-0 z-20" style={mascotStyle}>
				<img
					src="/corner.png"
					alt=""
					aria-hidden="true"
					className="w-full max-w-none select-none"
					style={{ transform: 'translate(-95%, 14%)' }}
				/>
			</div>

			{/* Footer - always visible */}
			<footer className="relative z-10 border-t border-border/30 font-mono flex-shrink-0 bg-background">
				<div className="container mx-auto px-6 py-4 max-w-6xl">
					<div className="flex items-center justify-between text-xs text-muted-foreground">
						<div className="flex items-center gap-6">
							<span>
								Built by{' '}
								<a
									href="https://bsky.app/profile/null.namespaces.me"
									target="_blank"
									rel="noopener noreferrer"
									className="text-accent hover:text-accent/80 transition-colors"
								>
									@null.namespaces.me
								</a>
							</span>
							<span>
								Contact:{' '}
								<a href="mailto:contact@wisp.place" className="text-accent hover:text-accent/80 transition-colors">
									contact@wisp.place
								</a>
							</span>
							<span>
								Legal:{' '}
								<a href="mailto:legal@wisp.place" className="text-accent hover:text-accent/80 transition-colors">
									legal@wisp.place
								</a>
							</span>
						</div>
						<div className="flex items-center gap-4">
							<a href="/acceptable-use" className="text-accent hover:text-accent/80 transition-colors">
								Acceptable Use Policy
							</a>
							<a href="/privacy" className="text-accent hover:text-accent/80 transition-colors">
								Privacy Policy
							</a>
						</div>
					</div>
				</div>
			</footer>

			{/* Site Configuration Modal */}
			<Dialog open={configuringSite !== null} onOpenChange={(open: boolean) => !open && setConfiguringSite(null)}>
				<DialogContent className="sm:max-w-2xl max-h-[90vh] overflow-y-auto">
					<DialogHeader>
						<DialogTitle>Configure Site</DialogTitle>
						<DialogDescription>Configure domains and settings for this site.</DialogDescription>
					</DialogHeader>
					{configuringSite && (
						<div className="space-y-4 py-4">
							<div className="p-3 bg-muted/30 rounded-lg">
								<p className="text-sm font-medium mb-1">Site:</p>
								<p className="font-mono text-sm">{configuringSite.display_name || configuringSite.rkey}</p>
							</div>

							<Tabs defaultValue="domains" className="w-full">
								<TabsList className="grid w-full grid-cols-2 bg-card border-b border-border/50 rounded-none h-auto p-0 flex-shrink-0">
									<TabsTrigger
										value="domains"
										className="text-muted-foreground hover:text-foreground hover:bg-muted/50 data-[state=active]:bg-transparent data-[state=active]:text-foreground"
									>
										Domains
									</TabsTrigger>
									<TabsTrigger
										value="settings"
										className="text-muted-foreground hover:text-foreground hover:bg-muted/50 data-[state=active]:bg-transparent data-[state=active]:text-foreground"
									>
										Settings
									</TabsTrigger>
								</TabsList>

								{/* Domains Tab */}
								<TabsContent value="domains" className="space-y-3 mt-4">
									<p className="text-sm font-medium">Available Domains:</p>

									{wispDomains.map((wispDomain) => {
										const domainId = `wisp:${wispDomain.domain}`
										return (
											<div
												key={domainId}
												className="flex items-center space-x-3 p-3 border rounded-lg hover:bg-muted/30"
											>
												<Checkbox
													id={domainId}
													checked={selectedDomains.has(domainId)}
													onCheckedChange={(checked: boolean | 'indeterminate') => {
														const newSelected = new Set(selectedDomains)
														if (checked) {
															newSelected.add(domainId)
														} else {
															newSelected.delete(domainId)
														}
														setSelectedDomains(newSelected)
													}}
												/>
												<Label htmlFor={domainId} className="flex-1 cursor-pointer">
													<div className="flex items-center justify-between">
														<span className="font-mono text-sm">{wispDomain.domain}</span>
														<Badge variant="secondary" className="text-xs ml-2">
															Wisp
														</Badge>
													</div>
												</Label>
											</div>
										)
									})}

									{customDomains
										.filter((d) => d.verified)
										.map((domain) => (
											<div
												key={domain.id}
												className="flex items-center space-x-3 p-3 border rounded-lg hover:bg-muted/30"
											>
												<Checkbox
													id={domain.id}
													checked={selectedDomains.has(domain.id)}
													onCheckedChange={(checked: boolean | 'indeterminate') => {
														const newSelected = new Set(selectedDomains)
														if (checked) {
															newSelected.add(domain.id)
														} else {
															newSelected.delete(domain.id)
														}
														setSelectedDomains(newSelected)
													}}
												/>
												<Label htmlFor={domain.id} className="flex-1 cursor-pointer">
													<div className="flex items-center justify-between">
														<span className="font-mono text-sm">{domain.domain}</span>
														<Badge variant="outline" className="text-xs ml-2">
															Custom
														</Badge>
													</div>
												</Label>
											</div>
										))}

									{customDomains.filter((d) => d.verified).length === 0 && wispDomains.length === 0 && (
										<p className="text-sm text-muted-foreground py-4 text-center">
											No domains available. Add a custom domain or claim a wisp.place subdomain.
										</p>
									)}

									<div className="p-3 bg-primary/5 rounded-lg border border-primary/20 mt-4">
										<p className="text-xs text-muted-foreground">
											<strong>Note:</strong> If no domains are selected, the site will be accessible at:{' '}
											<span className="font-mono">
												sites.wisp.place/{userInfo?.handle || '...'}/{configuringSite.rkey}
											</span>
										</p>
									</div>
								</TabsContent>

								{/* Settings Tab */}
								<TabsContent value="settings" className="space-y-4 mt-4">
									{/* Routing Mode */}
									<div className="space-y-3">
										<Label className="text-sm font-medium">Routing Mode</Label>
										<RadioGroup
											value={routingMode}
											onValueChange={(value: string) => setRoutingMode(value as RoutingMode)}
										>
											<div className="flex items-center space-x-3 p-3 border rounded-lg">
												<RadioGroupItem value="default" id="mode-default" />
												<Label htmlFor="mode-default" className="flex-1 cursor-pointer">
													<div>
														<p className="font-medium">Default</p>
														<p className="text-xs text-muted-foreground">Standard static file serving</p>
													</div>
												</Label>
											</div>
											<div className="flex items-center space-x-3 p-3 border rounded-lg">
												<RadioGroupItem value="spa" id="mode-spa" />
												<Label htmlFor="mode-spa" className="flex-1 cursor-pointer">
													<div>
														<p className="font-medium">SPA Mode</p>
														<p className="text-xs text-muted-foreground">Route all requests to a single file</p>
													</div>
												</Label>
											</div>
											{routingMode === 'spa' && (
												<div className="ml-7 space-y-2">
													<Label htmlFor="spa-file" className="text-sm">
														SPA File
													</Label>
													<Input
														id="spa-file"
														value={spaFile}
														onChange={(e: ChangeEvent<HTMLInputElement>) => setSpaFile(e.target.value)}
														placeholder="index.html"
													/>
												</div>
											)}
											<div className="flex items-center space-x-3 p-3 border rounded-lg">
												<RadioGroupItem value="directory" id="mode-directory" />
												<Label htmlFor="mode-directory" className="flex-1 cursor-pointer">
													<div>
														<p className="font-medium">Directory Listing</p>
														<p className="text-xs text-muted-foreground">Show directory contents on 404</p>
													</div>
												</Label>
											</div>
											<div className="flex items-center space-x-3 p-3 border rounded-lg">
												<RadioGroupItem value="custom404" id="mode-custom404" />
												<Label htmlFor="mode-custom404" className="flex-1 cursor-pointer">
													<div>
														<p className="font-medium">Custom 404 Page</p>
														<p className="text-xs text-muted-foreground">Serve custom error page</p>
													</div>
												</Label>
											</div>
											{routingMode === 'custom404' && (
												<div className="ml-7 space-y-2">
													<Label htmlFor="404-file" className="text-sm">
														404 File
													</Label>
													<Input
														id="404-file"
														value={custom404File}
														onChange={(e: ChangeEvent<HTMLInputElement>) => setCustom404File(e.target.value)}
														placeholder="404.html"
													/>
												</div>
											)}
										</RadioGroup>
									</div>

									{/* Index Files */}
									<div className="space-y-3">
										<Label className={`text-sm font-medium ${routingMode === 'spa' ? 'text-muted-foreground' : ''}`}>
											Index Files
											{routingMode === 'spa' && <span className="ml-2 text-xs">(disabled in SPA mode)</span>}
										</Label>
										<p className="text-xs text-muted-foreground">Files to try when serving a directory (in order)</p>
										<div className="space-y-2">
											{indexFiles.map((file, idx) => (
												<div key={file || idx} className="flex items-center gap-2">
													<Input
														value={file}
														onChange={(e: ChangeEvent<HTMLInputElement>) => {
															const newFiles = [...indexFiles]
															newFiles[idx] = e.target.value
															setIndexFiles(newFiles)
														}}
														placeholder="index.html"
														disabled={routingMode === 'spa'}
													/>
													<Button
														variant="outline"
														size="sm"
														onClick={() => {
															setIndexFiles(indexFiles.filter((_, i) => i !== idx))
														}}
														disabled={routingMode === 'spa'}
														className="w-20"
													>
														Remove
													</Button>
												</div>
											))}
											<div className="flex items-center gap-2">
												<Input
													value={newIndexFile}
													onChange={(e: ChangeEvent<HTMLInputElement>) => setNewIndexFile(e.target.value)}
													placeholder="Add index file..."
													onKeyDown={(e: ReactKeyboardEvent<HTMLInputElement>) => {
														if (e.key === 'Enter' && newIndexFile.trim()) {
															setIndexFiles([...indexFiles, newIndexFile.trim()])
															setNewIndexFile('')
														}
													}}
													disabled={routingMode === 'spa'}
												/>
												<Button
													variant="outline"
													size="sm"
													onClick={() => {
														if (newIndexFile.trim()) {
															setIndexFiles([...indexFiles, newIndexFile.trim()])
															setNewIndexFile('')
														}
													}}
													disabled={routingMode === 'spa'}
													className="w-20"
												>
													Add
												</Button>
											</div>
										</div>
									</div>

									{/* Clean URLs */}
									<div className="flex items-center space-x-3 p-3 border rounded-lg">
										<Checkbox
											id="clean-urls"
											checked={cleanUrls}
											onCheckedChange={(checked: boolean | 'indeterminate') => setCleanUrls(!!checked)}
										/>
										<Label htmlFor="clean-urls" className="flex-1 cursor-pointer">
											<div>
												<p className="font-medium">Clean URLs</p>
												<p className="text-xs text-muted-foreground">
													Serve /about as /about.html or /about/index.html
												</p>
											</div>
										</Label>
									</div>

									{/* CORS */}
									<div className="space-y-3">
										<div className="flex items-center space-x-3 p-3 border rounded-lg">
											<Checkbox
												id="cors-enabled"
												checked={corsEnabled}
												onCheckedChange={(checked: boolean | 'indeterminate') => setCorsEnabled(!!checked)}
											/>
											<Label htmlFor="cors-enabled" className="flex-1 cursor-pointer">
												<div>
													<p className="font-medium">Enable CORS</p>
													<p className="text-xs text-muted-foreground">Allow cross-origin requests</p>
												</div>
											</Label>
										</div>
										{corsEnabled && (
											<div className="ml-7 space-y-2">
												<Label htmlFor="cors-origin" className="text-sm">
													Allowed Origin
												</Label>
												<Input
													id="cors-origin"
													value={corsOrigin}
													onChange={(e: ChangeEvent<HTMLInputElement>) => setCorsOrigin(e.target.value)}
													placeholder="*"
												/>
												<p className="text-xs text-muted-foreground">
													Use * for all origins, or specify a domain like https://example.com
												</p>
											</div>
										)}
									</div>
								</TabsContent>
							</Tabs>
						</div>
					)}
					<DialogFooter className="flex flex-col sm:flex-row sm:justify-between gap-2">
						<Button
							variant="destructive"
							onClick={handleDeleteSite}
							disabled={isSavingConfig || isDeletingSite}
							className="sm:mr-auto"
						>
							{isDeletingSite ? (
								<>
									<Loader2 className="w-4 h-4 mr-2 animate-spin" />
									Deleting...
								</>
							) : (
								<>
									<Trash2 className="w-4 h-4 mr-2" />
									Delete Site
								</>
							)}
						</Button>
						<div className="flex flex-col sm:flex-row gap-2 w-full sm:w-auto">
							<Button
								variant="outline"
								onClick={() => setConfiguringSite(null)}
								disabled={isSavingConfig || isDeletingSite}
								className="w-full sm:w-auto"
							>
								Cancel
							</Button>
							<Button
								onClick={handleSaveSiteConfig}
								disabled={isSavingConfig || isDeletingSite}
								className="w-full sm:w-auto"
							>
								{isSavingConfig ? (
									<>
										<Loader2 className="w-4 h-4 mr-2 animate-spin" />
										Saving...
									</>
								) : (
									'Save'
								)}
							</Button>
						</div>
					</DialogFooter>
				</DialogContent>
			</Dialog>

			{/* Delete Site Confirmation Modal */}
			<Dialog open={deleteConfirmSite !== null} onOpenChange={(open: boolean) => !open && setDeleteConfirmSite(null)}>
				<DialogContent className="sm:max-w-md">
					<DialogHeader>
						<DialogTitle>Delete Site</DialogTitle>
						<DialogDescription>
							Are you sure you want to delete "{deleteConfirmSite?.display_name || deleteConfirmSite?.rkey}"? This
							action cannot be undone.
						</DialogDescription>
					</DialogHeader>
					<DialogFooter className="flex flex-col sm:flex-row gap-2 sm:justify-end">
						<Button
							variant="outline"
							onClick={() => setDeleteConfirmSite(null)}
							disabled={isDeletingSite}
							className="w-full sm:w-auto"
						>
							Cancel
						</Button>
						<Button
							variant="destructive"
							onClick={handleDeleteSite}
							disabled={isDeletingSite}
							className="w-full sm:w-auto"
						>
							{isDeletingSite ? (
								<>
									<Loader2 className="w-4 h-4 mr-2 animate-spin" />
									Deleting...
								</>
							) : (
								'Delete'
							)}
						</Button>
					</DialogFooter>
				</DialogContent>
			</Dialog>
		</div>
	)
}

function AcceptableUsePage() {
	// Redirect to public acceptable use page
	useEffect(() => {
		window.location.href = '/acceptable-use'
	}, [])

	// Show loading state while redirecting
	return (
		<div className="w-full min-h-screen bg-background flex items-center justify-center">
			<Loader2 className="w-8 h-8 animate-spin text-muted-foreground" />
		</div>
	)
}

function App() {
	return (
		<BrowserRouter>
			<Routes>
				<Route path="/editor" element={<Dashboard />} />
				<Route path="/editor/acceptable-use" element={<AcceptableUsePage />} />
			</Routes>
		</BrowserRouter>
	)
}

const root = createRoot(document.getElementById('elysia')!)
root.render(
	<Layout className="gap-6">
		<App />
	</Layout>,
)
