import React, { useState, useEffect, useCallback, useRef } from "react";
import { createRoot } from "react-dom/client";

interface Project {
	path: string;
	name: string;
	color: string;
}

interface AggregatedTask {
	id: string;
	title: string;
	status: string;
	priority?: string;
	description?: string;
	assignee: string[];
	labels: string[];
	projectName: string;
	projectColor: string;
	projectPath: string;
	createdDate?: string;
	updatedDate?: string;
}

interface WebSocketMessage {
	type: "init" | "update";
	projects: Project[];
	tasks: AggregatedTask[];
	timestamp?: number;
}

function App() {
	const [projects, setProjects] = useState<Project[]>([]);
	const [tasks, setTasks] = useState<AggregatedTask[]>([]);
	const [connected, setConnected] = useState(false);
	const [lastUpdate, setLastUpdate] = useState<Date | null>(null);
	const [filter, setFilter] = useState<string>("");
	const [selectedProject, setSelectedProject] = useState<string | null>(null);
	const [actionError, setActionError] = useState<string | null>(null);
	const wsRef = useRef<WebSocket | null>(null);
	const reconnectTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);

	const handleArchiveTask = async (task: AggregatedTask) => {
		try {
			const response = await fetch("/api/tasks/archive", {
				method: "POST",
				headers: { "Content-Type": "application/json" },
				body: JSON.stringify({ projectPath: task.projectPath, taskId: task.id }),
			});
			if (!response.ok) {
				const data = await response.json();
				throw new Error(data.error || "Failed to archive task");
			}
			setActionError(null);
		} catch (error) {
			setActionError(error instanceof Error ? error.message : "Failed to archive task");
			setTimeout(() => setActionError(null), 3000);
		}
	};

	const handleDeleteTask = async (task: AggregatedTask) => {
		if (!confirm(`Are you sure you want to delete "${task.title}"? This cannot be undone.`)) {
			return;
		}
		try {
			const response = await fetch("/api/tasks/delete", {
				method: "DELETE",
				headers: { "Content-Type": "application/json" },
				body: JSON.stringify({ projectPath: task.projectPath, taskId: task.id }),
			});
			if (!response.ok) {
				const data = await response.json();
				throw new Error(data.error || "Failed to delete task");
			}
			setActionError(null);
		} catch (error) {
			setActionError(error instanceof Error ? error.message : "Failed to delete task");
			setTimeout(() => setActionError(null), 3000);
		}
	};

	const handleUpdateTask = async (task: AggregatedTask, updates: Partial<AggregatedTask>) => {
		try {
			const response = await fetch("/api/tasks/update", {
				method: "PATCH",
				headers: { "Content-Type": "application/json" },
				body: JSON.stringify({
					projectPath: task.projectPath,
					taskId: task.id,
					...updates,
				}),
			});
			if (!response.ok) {
				const data = await response.json();
				throw new Error(data.error || "Failed to update task");
			}
			setActionError(null);
		} catch (error) {
			setActionError(error instanceof Error ? error.message : "Failed to update task");
			setTimeout(() => setActionError(null), 3000);
		}
	};

	const connectWebSocket = useCallback(() => {
		const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
		const ws = new WebSocket(`${protocol}//${window.location.host}`);

		ws.onopen = () => {
			setConnected(true);
			console.log("WebSocket connected");
		};

		ws.onmessage = (event) => {
			try {
				const data: WebSocketMessage = JSON.parse(event.data);
				if (data.type === "init" || data.type === "update") {
					setProjects(data.projects);
					setTasks(data.tasks);
					setLastUpdate(new Date());
				}
			} catch (error) {
				console.error("Failed to parse WebSocket message:", error);
			}
		};

		ws.onclose = () => {
			setConnected(false);
			console.log("WebSocket disconnected, reconnecting...");
			reconnectTimeoutRef.current = setTimeout(connectWebSocket, 3000);
		};

		ws.onerror = (error) => {
			console.error("WebSocket error:", error);
		};

		wsRef.current = ws;
	}, []);

	useEffect(() => {
		connectWebSocket();
		return () => {
			wsRef.current?.close();
			if (reconnectTimeoutRef.current) {
				clearTimeout(reconnectTimeoutRef.current);
			}
		};
	}, [connectWebSocket]);

	// Group tasks by status
	const statuses = ["To Do", "In Progress", "Done", "Won't Do"];
	const tasksByStatus = statuses.reduce(
		(acc, status) => {
			acc[status] = tasks.filter((t) => {
				const statusMatch = t.status.toLowerCase() === status.toLowerCase();
				const projectMatch = !selectedProject || t.projectName === selectedProject;
				const filterMatch =
					!filter ||
					t.title.toLowerCase().includes(filter.toLowerCase()) ||
					t.projectName.toLowerCase().includes(filter.toLowerCase());
				return statusMatch && projectMatch && filterMatch;
			});
			return acc;
		},
		{} as Record<string, AggregatedTask[]>,
	);

	return (
		<div
			style={{
				minHeight: "100vh",
				backgroundColor: "#0f172a",
				color: "#e2e8f0",
				fontFamily: "system-ui, -apple-system, sans-serif",
			}}
		>
			{/* Header */}
			<header
				style={{
					padding: "1rem 2rem",
					backgroundColor: "#1e293b",
					borderBottom: "1px solid #334155",
					display: "flex",
					justifyContent: "space-between",
					alignItems: "center",
				}}
			>
				<div style={{ display: "flex", alignItems: "center", gap: "1rem" }}>
					<h1 style={{ margin: 0, fontSize: "1.5rem", fontWeight: 600 }}>Backlog Aggregator</h1>
					<span
						style={{
							padding: "0.25rem 0.5rem",
							borderRadius: "9999px",
							fontSize: "0.75rem",
							backgroundColor: connected ? "#22c55e" : "#ef4444",
							color: "white",
						}}
					>
						{connected ? "Live" : "Reconnecting..."}
					</span>
				</div>
				<div style={{ display: "flex", alignItems: "center", gap: "1rem" }}>
					{actionError && (
						<span
							style={{
								padding: "0.25rem 0.75rem",
								borderRadius: "0.25rem",
								fontSize: "0.75rem",
								backgroundColor: "#ef4444",
								color: "white",
							}}
						>
							{actionError}
						</span>
					)}
					<span style={{ fontSize: "0.875rem", color: "#94a3b8" }}>
						{projects.length} projects | {tasks.length} tasks
						{lastUpdate && ` | Updated ${lastUpdate.toLocaleTimeString()}`}
					</span>
				</div>
			</header>

			{/* Project Filter Bar */}
			<div
				style={{
					padding: "1rem 2rem",
					backgroundColor: "#1e293b",
					display: "flex",
					gap: "0.5rem",
					flexWrap: "wrap",
					alignItems: "center",
				}}
			>
				<input
					type="text"
					placeholder="Filter tasks..."
					value={filter}
					onChange={(e) => setFilter(e.target.value)}
					style={{
						padding: "0.5rem 1rem",
						borderRadius: "0.375rem",
						border: "1px solid #334155",
						backgroundColor: "#0f172a",
						color: "#e2e8f0",
						minWidth: "200px",
					}}
				/>
				<button
					onClick={() => setSelectedProject(null)}
					style={{
						padding: "0.5rem 1rem",
						borderRadius: "0.375rem",
						border: selectedProject === null ? "2px solid #3b82f6" : "1px solid #334155",
						backgroundColor: selectedProject === null ? "#1e40af" : "#0f172a",
						color: "#e2e8f0",
						cursor: "pointer",
					}}
				>
					All Projects
				</button>
				{projects.map((project) => (
					<button
						key={project.path}
						onClick={() => setSelectedProject(project.name)}
						style={{
							padding: "0.5rem 1rem",
							borderRadius: "0.375rem",
							border: selectedProject === project.name ? `2px solid ${project.color}` : "1px solid #334155",
							backgroundColor: selectedProject === project.name ? project.color + "33" : "#0f172a",
							color: "#e2e8f0",
							cursor: "pointer",
							display: "flex",
							alignItems: "center",
							gap: "0.5rem",
						}}
					>
						<span
							style={{
								width: "0.75rem",
								height: "0.75rem",
								borderRadius: "50%",
								backgroundColor: project.color,
							}}
						/>
						{project.name}
					</button>
				))}
			</div>

			{/* Kanban Board */}
			<div
				style={{
					padding: "2rem",
					display: "grid",
					gridTemplateColumns: "repeat(4, 1fr)",
					gap: "1.5rem",
					minHeight: "calc(100vh - 180px)",
				}}
			>
				{statuses.map((status) => (
					<div
						key={status}
						style={{
							backgroundColor: "#1e293b",
							borderRadius: "0.5rem",
							padding: "1rem",
							display: "flex",
							flexDirection: "column",
						}}
					>
						{/* Column Header */}
						<div
							style={{
								display: "flex",
								justifyContent: "space-between",
								alignItems: "center",
								marginBottom: "1rem",
								paddingBottom: "0.5rem",
								borderBottom: "1px solid #334155",
							}}
						>
							<h2 style={{ margin: 0, fontSize: "1rem", fontWeight: 600 }}>{status}</h2>
							<span
								style={{
									backgroundColor: "#334155",
									padding: "0.25rem 0.5rem",
									borderRadius: "9999px",
									fontSize: "0.75rem",
								}}
							>
								{tasksByStatus[status]?.length || 0}
							</span>
						</div>

						{/* Tasks */}
						<div style={{ display: "flex", flexDirection: "column", gap: "0.75rem", flex: 1, overflowY: "auto" }}>
							{tasksByStatus[status]?.map((task) => (
								<TaskCard
									key={`${task.projectPath}:${task.id}`}
									task={task}
									onArchive={handleArchiveTask}
									onDelete={handleDeleteTask}
									onUpdate={handleUpdateTask}
									statuses={statuses}
								/>
							))}
							{(!tasksByStatus[status] || tasksByStatus[status].length === 0) && (
								<div style={{ color: "#64748b", textAlign: "center", padding: "2rem", fontSize: "0.875rem" }}>
									No tasks
								</div>
							)}
						</div>
					</div>
				))}
			</div>
		</div>
	);
}

interface TaskCardProps {
	task: AggregatedTask;
	onArchive: (task: AggregatedTask) => void;
	onDelete: (task: AggregatedTask) => void;
	onUpdate: (task: AggregatedTask, updates: Partial<AggregatedTask>) => void;
	statuses: string[];
}

function TaskCard({ task, onArchive, onDelete, onUpdate, statuses }: TaskCardProps) {
	const [expanded, setExpanded] = useState(false);
	const [isHovering, setIsHovering] = useState(false);
	const [editingField, setEditingField] = useState<string | null>(null);
	const [editValue, setEditValue] = useState("");

	const priorityColors: Record<string, string> = {
		high: "#ef4444",
		medium: "#f59e0b",
		low: "#22c55e",
	};

	const priorities = ["high", "medium", "low"];

	const handleArchiveClick = (e: React.MouseEvent) => {
		e.stopPropagation();
		onArchive(task);
	};

	const handleDeleteClick = (e: React.MouseEvent) => {
		e.stopPropagation();
		onDelete(task);
	};

	const startEditing = (field: string, currentValue: string, e: React.MouseEvent) => {
		e.stopPropagation();
		setEditingField(field);
		setEditValue(currentValue);
	};

	const saveEdit = async (e: React.MouseEvent | React.KeyboardEvent) => {
		e.stopPropagation();
		if (editingField && editValue !== task[editingField as keyof AggregatedTask]) {
			onUpdate(task, { [editingField]: editValue });
		}
		setEditingField(null);
		setEditValue("");
	};

	const cancelEdit = (e: React.MouseEvent | React.KeyboardEvent) => {
		e.stopPropagation();
		setEditingField(null);
		setEditValue("");
	};

	const handleKeyDown = (e: React.KeyboardEvent) => {
		if (e.key === "Enter" && !e.shiftKey) {
			saveEdit(e);
		} else if (e.key === "Escape") {
			cancelEdit(e);
		}
	};

	const handleStatusChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
		e.stopPropagation();
		onUpdate(task, { status: e.target.value });
	};

	const handlePriorityChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
		e.stopPropagation();
		onUpdate(task, { priority: e.target.value });
	};

	const inputStyle: React.CSSProperties = {
		backgroundColor: "#1e293b",
		border: "1px solid #3b82f6",
		borderRadius: "0.25rem",
		padding: "0.25rem 0.5rem",
		color: "#e2e8f0",
		fontSize: "inherit",
		width: "100%",
		outline: "none",
	};

	const selectStyle: React.CSSProperties = {
		backgroundColor: "#1e293b",
		border: "1px solid #334155",
		borderRadius: "0.25rem",
		padding: "0.125rem 0.25rem",
		color: "#e2e8f0",
		fontSize: "0.625rem",
		cursor: "pointer",
		outline: "none",
	};

	return (
		<div
			onClick={() => !editingField && setExpanded(!expanded)}
			onMouseEnter={() => setIsHovering(true)}
			onMouseLeave={() => setIsHovering(false)}
			style={{
				backgroundColor: "#0f172a",
				borderRadius: "0.375rem",
				padding: "0.75rem",
				cursor: editingField ? "default" : "pointer",
				borderLeft: `4px solid ${task.projectColor}`,
				transition: "transform 0.1s, box-shadow 0.1s",
				position: "relative",
				transform: isHovering && !editingField ? "translateY(-1px)" : "translateY(0)",
				boxShadow: isHovering && !editingField ? "0 4px 6px -1px rgba(0, 0, 0, 0.3)" : "none",
			}}
		>
			{/* Action buttons - shown on hover */}
			{isHovering && !editingField && (
				<div
					style={{
						position: "absolute",
						top: "-8px",
						right: "-8px",
						display: "flex",
						gap: "4px",
						zIndex: 10,
					}}
				>
					<button
						onClick={handleArchiveClick}
						title="Archive task"
						style={{
							width: "24px",
							height: "24px",
							borderRadius: "50%",
							border: "none",
							backgroundColor: "#3b82f6",
							color: "white",
							cursor: "pointer",
							display: "flex",
							alignItems: "center",
							justifyContent: "center",
							fontSize: "12px",
							fontWeight: "bold",
							boxShadow: "0 2px 4px rgba(0,0,0,0.3)",
						}}
					>
						↑
					</button>
					<button
						onClick={handleDeleteClick}
						title="Delete task"
						style={{
							width: "24px",
							height: "24px",
							borderRadius: "50%",
							border: "none",
							backgroundColor: "#ef4444",
							color: "white",
							cursor: "pointer",
							display: "flex",
							alignItems: "center",
							justifyContent: "center",
							fontSize: "14px",
							fontWeight: "bold",
							boxShadow: "0 2px 4px rgba(0,0,0,0.3)",
						}}
					>
						×
					</button>
				</div>
			)}

			{/* Task Header */}
			<div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start", gap: "0.5rem" }}>
				<div style={{ flex: 1 }}>
					{editingField === "title" ? (
						<div style={{ display: "flex", gap: "0.25rem", alignItems: "center" }}>
							<input
								type="text"
								value={editValue}
								onChange={(e) => setEditValue(e.target.value)}
								onKeyDown={handleKeyDown}
								onClick={(e) => e.stopPropagation()}
								autoFocus
								style={{ ...inputStyle, fontSize: "0.875rem", fontWeight: 500 }}
							/>
							<button onClick={saveEdit} style={{ ...selectStyle, backgroundColor: "#22c55e" }}>✓</button>
							<button onClick={cancelEdit} style={{ ...selectStyle, backgroundColor: "#ef4444" }}>✕</button>
						</div>
					) : (
						<div
							style={{ fontSize: "0.875rem", fontWeight: 500, marginBottom: "0.25rem", cursor: "text" }}
							onClick={(e) => startEditing("title", task.title, e)}
							title="Click to edit title"
						>
							{task.title}
						</div>
					)}
					<div style={{ fontSize: "0.75rem", color: "#64748b", display: "flex", alignItems: "center", gap: "0.5rem" }}>
						<span>{task.id} | {task.projectName}</span>
						<select
							value={task.status}
							onChange={handleStatusChange}
							onClick={(e) => e.stopPropagation()}
							style={{ ...selectStyle, marginLeft: "0.25rem" }}
							title="Change status"
						>
							{statuses.map((s) => (
								<option key={s} value={s}>{s}</option>
							))}
						</select>
					</div>
				</div>
				<select
					value={task.priority || ""}
					onChange={handlePriorityChange}
					onClick={(e) => e.stopPropagation()}
					style={{
						...selectStyle,
						backgroundColor: task.priority ? priorityColors[task.priority.toLowerCase()] + "22" : "#334155",
						color: task.priority ? priorityColors[task.priority.toLowerCase()] : "#94a3b8",
						fontWeight: 500,
						textTransform: "uppercase",
					}}
					title="Change priority"
				>
					<option value="">No priority</option>
					{priorities.map((p) => (
						<option key={p} value={p}>{p}</option>
					))}
				</select>
			</div>

			{/* Labels */}
			{task.labels && task.labels.length > 0 && (
				<div style={{ display: "flex", gap: "0.25rem", flexWrap: "wrap", marginTop: "0.5rem" }}>
					{task.labels.map((label) => (
						<span
							key={label}
							style={{
								padding: "0.125rem 0.375rem",
								borderRadius: "0.25rem",
								fontSize: "0.625rem",
								backgroundColor: "#334155",
								color: "#94a3b8",
							}}
						>
							{label}
						</span>
					))}
				</div>
			)}

			{/* Expanded Details */}
			{expanded && (
				<div
					style={{
						marginTop: "0.75rem",
						paddingTop: "0.75rem",
						borderTop: "1px solid #334155",
					}}
				>
					{editingField === "description" ? (
						<div style={{ display: "flex", flexDirection: "column", gap: "0.5rem" }}>
							<textarea
								value={editValue}
								onChange={(e) => setEditValue(e.target.value)}
								onKeyDown={(e) => {
									if (e.key === "Escape") cancelEdit(e);
									// Allow Enter for newlines in textarea, use Ctrl+Enter to save
									if (e.key === "Enter" && e.ctrlKey) saveEdit(e);
								}}
								onClick={(e) => e.stopPropagation()}
								autoFocus
								rows={5}
								style={{
									...inputStyle,
									fontSize: "0.8rem",
									resize: "vertical",
									minHeight: "80px",
								}}
								placeholder="Enter description..."
							/>
							<div style={{ display: "flex", gap: "0.25rem", justifyContent: "flex-end" }}>
								<span style={{ fontSize: "0.625rem", color: "#64748b", marginRight: "auto" }}>
									Ctrl+Enter to save, Escape to cancel
								</span>
								<button onClick={saveEdit} style={{ ...selectStyle, backgroundColor: "#22c55e", padding: "0.25rem 0.5rem" }}>Save</button>
								<button onClick={cancelEdit} style={{ ...selectStyle, backgroundColor: "#ef4444", padding: "0.25rem 0.5rem" }}>Cancel</button>
							</div>
						</div>
					) : (
						<div
							onClick={(e) => startEditing("description", task.description || "", e)}
							style={{
								fontSize: "0.8rem",
								color: "#94a3b8",
								whiteSpace: "pre-wrap",
								cursor: "text",
								minHeight: "20px",
							}}
							title="Click to edit description"
						>
							{task.description ? (
								<>
									{task.description.slice(0, 500)}
									{task.description.length > 500 && "..."}
								</>
							) : (
								<span style={{ fontStyle: "italic", color: "#64748b" }}>Click to add description...</span>
							)}
						</div>
					)}
				</div>
			)}

			{/* Assignees */}
			{task.assignee && task.assignee.length > 0 && (
				<div style={{ marginTop: "0.5rem", fontSize: "0.75rem", color: "#64748b" }}>
					{task.assignee.join(", ")}
				</div>
			)}
		</div>
	);
}

// Mount the app
const root = createRoot(document.getElementById("root")!);
root.render(<App />);
