<script lang="ts">
	import { getContext, onDestroy } from "svelte";
	import {
		Modal,
		Button,
		Input,
		Textarea,
		Select,
		AssigneePicker,
		Icon,
	} from "$lib/components/ui";
	import type { KanbanCard } from "$lib/supabase/types";
	import type { SupabaseClient } from "@supabase/supabase-js";
	import type { Database } from "$lib/supabase/types";

	let isMounted = $state(true);
	onDestroy(() => {
		isMounted = false;
	});

	interface ChecklistItem {
		id: string;
		card_id: string;
		title: string;
		completed: boolean;
		position: number;
	}

	interface Comment {
		id: string;
		card_id: string;
		user_id: string;
		content: string;
		created_at: string;
		profiles?: { full_name: string | null; email: string };
	}

	interface Member {
		id: string;
		user_id: string;
		profiles: {
			id: string;
			full_name: string | null;
			email: string;
			avatar_url: string | null;
		};
	}

	interface OrgTag {
		id: string;
		name: string;
		color: string | null;
	}

	interface Props {
		card: KanbanCard | null;
		isOpen: boolean;
		onClose: () => void;
		onUpdate: (card: KanbanCard) => void;
		onDelete: (cardId: string) => void;
		mode?: "edit" | "create";
		columnId?: string;
		userId?: string;
		orgId?: string;
		onCreate?: (card: KanbanCard) => void;
		members?: Member[];
	}

	let {
		card,
		isOpen,
		onClose,
		onUpdate,
		onDelete,
		mode = "edit",
		columnId,
		userId,
		orgId,
		onCreate,
		members = [],
	}: Props = $props();

	const supabase = getContext<SupabaseClient<Database>>("supabase");

	let title = $state("");
	let description = $state("");
	let checklist = $state<ChecklistItem[]>([]);
	let comments = $state<Comment[]>([]);
	let newItemTitle = $state("");
	let newComment = $state("");
	let assigneeId = $state<string | null>(null);
	let dueDate = $state<string>("");
	let priority = $state<string>("medium");
	let isLoading = $state(false);
	let isSaving = $state(false);
	let showAssigneePicker = $state(false);

	// Tags state
	let orgTags = $state<OrgTag[]>([]);
	let cardTagIds = $state<Set<string>>(new Set());
	let newTagName = $state("");
	let showTagInput = $state(false);
	let editingTagId = $state<string | null>(null);
	let editTagName = $state("");
	let editTagColor = $state("");
	let showTagManager = $state(false);

	const TAG_COLORS = [
		"#00A3E0",
		"#33E000",
		"#E03D00",
		"#FFAB00",
		"#A855F7",
		"#EC4899",
		"#6366F1",
	];

	$effect(() => {
		if (isOpen) {
			if (mode === "edit" && card) {
				title = card.title;
				description = card.description ?? "";
				assigneeId = card.assignee_id ?? null;
				dueDate = card.due_date
					? new Date(card.due_date).toISOString().split("T")[0]
					: "";
				priority = card.priority ?? "medium";
				loadChecklist();
				loadComments();
				loadTags();
			} else if (mode === "create") {
				title = "";
				description = "";
				assigneeId = null;
				dueDate = "";
				priority = "medium";
				checklist = [];
				comments = [];
				cardTagIds = new Set();
				loadOrgTags();
			}
		}
	});

	async function loadChecklist() {
		if (!card || !isMounted) return;
		isLoading = true;

		const { data } = await supabase
			.from("kanban_checklist_items")
			.select("*")
			.eq("card_id", card.id)
			.order("position");

		if (!isMounted) return;
		checklist = (data ?? []) as ChecklistItem[];
		isLoading = false;
	}

	async function loadComments() {
		if (!card || !isMounted) return;

		const { data } = await supabase
			.from("kanban_comments")
			.select(
				`
				id,
				card_id,
				user_id,
				content,
				created_at,
				profiles:user_id (full_name, email)
			`,
			)
			.eq("card_id", card.id)
			.order("created_at", { ascending: true });

		if (!isMounted) return;
		comments = (data ?? []) as Comment[];
	}

	async function loadOrgTags() {
		if (!orgId) return;
		const { data } = await supabase
			.from("tags")
			.select("id, name, color")
			.eq("org_id", orgId)
			.order("name");
		if (!isMounted) return;
		orgTags = (data ?? []) as OrgTag[];
	}

	async function loadTags() {
		await loadOrgTags();
		if (!card) return;
		const { data } = await supabase
			.from("card_tags")
			.select("tag_id")
			.eq("card_id", card.id);
		if (!isMounted) return;
		cardTagIds = new Set((data ?? []).map((t) => t.tag_id));
	}

	async function toggleTag(tagId: string) {
		if (!card) return;
		if (cardTagIds.has(tagId)) {
			await supabase
				.from("card_tags")
				.delete()
				.eq("card_id", card.id)
				.eq("tag_id", tagId);
			cardTagIds.delete(tagId);
			cardTagIds = new Set(cardTagIds);
		} else {
			await supabase
				.from("card_tags")
				.insert({ card_id: card.id, tag_id: tagId });
			cardTagIds.add(tagId);
			cardTagIds = new Set(cardTagIds);
		}
	}

	async function createTag() {
		if (!newTagName.trim() || !orgId) return;
		const color = TAG_COLORS[orgTags.length % TAG_COLORS.length];
		const { data: newTag, error } = await supabase
			.from("tags")
			.insert({ name: newTagName.trim(), org_id: orgId, color })
			.select()
			.single();
		if (!error && newTag) {
			orgTags = [...orgTags, newTag as OrgTag];
			if (card) {
				await supabase
					.from("card_tags")
					.insert({ card_id: card.id, tag_id: newTag.id });
				cardTagIds.add(newTag.id);
				cardTagIds = new Set(cardTagIds);
			}
		}
		newTagName = "";
		showTagInput = false;
	}

	function startEditTag(tag: OrgTag) {
		editingTagId = tag.id;
		editTagName = tag.name;
		editTagColor = tag.color || TAG_COLORS[0];
	}

	async function saveEditTag() {
		if (!editingTagId || !editTagName.trim()) return;
		const { error } = await supabase
			.from("tags")
			.update({ name: editTagName.trim(), color: editTagColor })
			.eq("id", editingTagId);
		if (!error) {
			orgTags = orgTags.map((t) =>
				t.id === editingTagId
					? { ...t, name: editTagName.trim(), color: editTagColor }
					: t,
			);
		}
		editingTagId = null;
	}

	async function deleteTag(tagId: string) {
		if (!confirm("Delete this tag from the organization?")) return;
		const { error } = await supabase.from("tags").delete().eq("id", tagId);
		if (!error) {
			orgTags = orgTags.filter((t) => t.id !== tagId);
			cardTagIds.delete(tagId);
			cardTagIds = new Set(cardTagIds);
		}
	}

	async function handleSave() {
		if (!isMounted) return;
		if (mode === "create") {
			await handleCreate();
			return;
		}

		if (!card) return;
		isSaving = true;

		const { error } = await supabase
			.from("kanban_cards")
			.update({
				title,
				description: description || null,
				assignee_id: assigneeId,
				due_date: dueDate || null,
				priority,
			})
			.eq("id", card.id);

		if (!error) {
			onUpdate({
				...card,
				title,
				description: description || null,
				assignee_id: assigneeId,
				due_date: dueDate || null,
				priority,
			} as KanbanCard);
		}
		isSaving = false;
	}

	async function handleCreate() {
		if (!title.trim() || !columnId || !userId) return;
		isSaving = true;

		const { data: column } = await supabase
			.from("kanban_columns")
			.select("cards:kanban_cards(count)")
			.eq("id", columnId)
			.single();

		const cards = (column as Record<string, unknown> | null)?.cards as
			| { count: number }[]
			| undefined;
		const position = cards?.[0]?.count ?? 0;

		const { data: newCard, error } = await supabase
			.from("kanban_cards")
			.insert({
				column_id: columnId,
				title,
				description: description || null,
				priority: priority || null,
				due_date: dueDate || null,
				assignee_id: assigneeId || null,
				position,
				created_by: userId,
			})
			.select()
			.single();

		if (!error && newCard) {
			// Persist checklist items added during creation
			if (checklist.length > 0) {
				await supabase.from("kanban_checklist_items").insert(
					checklist.map((item, i) => ({
						card_id: newCard.id,
						title: item.title,
						position: i,
						completed: false,
					})),
				);
			}
			// Persist tags assigned during creation
			if (cardTagIds.size > 0) {
				await supabase.from("card_tags").insert(
					[...cardTagIds].map((tagId) => ({
						card_id: newCard.id,
						tag_id: tagId,
					})),
				);
			}
			onCreate?.(newCard as KanbanCard);
			onClose();
		}
		isSaving = false;
	}

	async function handleAddItem() {
		if (!newItemTitle.trim()) return;

		if (mode === "create") {
			// In create mode, add items locally (no card ID yet)
			checklist = [
				...checklist,
				{
					id: `temp-${Date.now()}`,
					card_id: "",
					title: newItemTitle.trim(),
					completed: false,
					position: checklist.length,
				},
			];
			newItemTitle = "";
			return;
		}

		if (!card) return;

		const position = checklist.length;
		const { data, error } = await supabase
			.from("kanban_checklist_items")
			.insert({
				card_id: card.id,
				title: newItemTitle,
				position,
				completed: false,
			})
			.select()
			.single();

		if (!error && data) {
			checklist = [...checklist, data as ChecklistItem];
			newItemTitle = "";
		}
	}

	async function handleAddComment() {
		if (!card || !newComment.trim() || !userId) return;

		const { data, error } = await supabase
			.from("kanban_comments")
			.insert({
				card_id: card.id,
				user_id: userId,
				content: newComment,
			})
			.select(
				`
				id,
				card_id,
				user_id,
				content,
				created_at,
				profiles:user_id (full_name, email)
			`,
			)
			.single();

		if (!error && data) {
			comments = [...comments, data as Comment];
			newComment = "";
		}
	}

	async function toggleItem(item: ChecklistItem) {
		const { error } = await supabase
			.from("kanban_checklist_items")
			.update({ completed: !item.completed })
			.eq("id", item.id);

		if (!error) {
			checklist = checklist.map((i) =>
				i.id === item.id ? { ...i, completed: !i.completed } : i,
			);
		}
	}

	async function deleteItem(itemId: string) {
		const { error } = await supabase
			.from("kanban_checklist_items")
			.delete()
			.eq("id", itemId);

		if (!error) {
			checklist = checklist.filter((i) => i.id !== itemId);
		}
	}

	function formatDate(dateStr: string): string {
		return new Date(dateStr).toLocaleDateString("en-US", {
			month: "short",
			day: "numeric",
			hour: "2-digit",
			minute: "2-digit",
		});
	}

	function getAssignee(id: string | null) {
		if (!id) return null;
		return members.find((m) => m.user_id === id);
	}

	async function handleDelete() {
		if (!card || !confirm("Delete this card?")) return;

		await supabase.from("kanban_cards").delete().eq("id", card.id);

		onDelete(card.id);
		onClose();
	}

	const completedCount = $derived(
		checklist.filter((i) => i.completed).length,
	);
	const progress = $derived(
		checklist.length > 0 ? (completedCount / checklist.length) * 100 : 0,
	);
</script>

<Modal
	{isOpen}
	{onClose}
	title={mode === "create" ? "Add Card" : "Card Details"}
	size="lg"
>
	{#if mode === "create" || card}
		<div class="space-y-5">
			<Input label="Title" bind:value={title} placeholder="Card title" />

			<Textarea
				label="Description"
				bind:value={description}
				placeholder="Add a more detailed description..."
				rows={3}
			/>

			<!-- Tags -->
			<div>
				<div class="flex items-center justify-between mb-2">
					<span class="px-3 font-bold font-body text-body text-white"
						>Tags</span
					>
					<button
						type="button"
						class="text-xs text-light/40 hover:text-light transition-colors"
						onclick={() => (showTagManager = !showTagManager)}
					>
						{showTagManager ? "Done" : "Manage"}
					</button>
				</div>

				{#if showTagManager}
					<!-- Tag Manager: edit/delete/create tags -->
					<div class="space-y-2 mb-3 p-3 bg-background rounded-2xl">
						{#each orgTags as tag}
							<div class="flex items-center gap-2 group">
								{#if editingTagId === tag.id}
									<div class="flex items-center gap-2 flex-1">
										<input
											type="color"
											class="w-6 h-6 rounded cursor-pointer border-0 bg-transparent"
											bind:value={editTagColor}
										/>
										<input
											type="text"
											class="bg-dark border border-primary rounded-lg px-2 py-1 text-sm text-white flex-1 focus:outline-none"
											bind:value={editTagName}
											onkeydown={(e) => {
												if (e.key === "Enter")
													saveEditTag();
												if (e.key === "Escape") {
													editingTagId = null;
												}
											}}
										/>
										<button
											type="button"
											class="text-primary text-xs font-bold"
											onclick={saveEditTag}>Save</button
										>
										<button
											type="button"
											class="text-light/40 text-xs"
											onclick={() =>
												(editingTagId = null)}
											>Cancel</button
										>
									</div>
								{:else}
									<span
										class="w-3 h-3 rounded-sm shrink-0"
										style="background-color: {tag.color ||
											'#00A3E0'}"
									></span>
									<span
										class="text-sm text-light flex-1 truncate"
										>{tag.name}</span
									>
									<button
										type="button"
										class="opacity-0 group-hover:opacity-100 p-0.5 text-light/40 hover:text-light transition-all"
										onclick={() => startEditTag(tag)}
										aria-label="Edit tag"
									>
										<span
											class="material-symbols-rounded"
											style="font-size: 16px; font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 16;"
											>edit</span
										>
									</button>
									<button
										type="button"
										class="opacity-0 group-hover:opacity-100 p-0.5 text-light/40 hover:text-error transition-all"
										onclick={() => deleteTag(tag.id)}
										aria-label="Delete tag"
									>
										<span
											class="material-symbols-rounded"
											style="font-size: 16px; font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 16;"
											>delete</span
										>
									</button>
								{/if}
							</div>
						{/each}
						<!-- Inline create new tag -->
						<div
							class="flex items-center gap-2 pt-1 border-t border-light/10"
						>
							<input
								type="text"
								class="bg-dark border border-light/20 rounded-lg px-2 py-1 text-sm text-white flex-1 focus:outline-none focus:border-primary"
								placeholder="New tag name..."
								bind:value={newTagName}
								onkeydown={(e) =>
									e.key === "Enter" && createTag()}
							/>
							<button
								type="button"
								class="text-primary text-xs font-bold hover:text-primary/80 whitespace-nowrap"
								onclick={createTag}
								disabled={!newTagName.trim()}
							>
								+ Add
							</button>
						</div>
					</div>
				{/if}

				<!-- Tag toggle chips -->
				<div class="flex flex-wrap gap-2 items-center">
					{#each orgTags as tag}
						<button
							type="button"
							class="rounded-[4px] px-2 py-1 font-body font-bold text-[13px] leading-none transition-all border-2"
							style="background-color: {cardTagIds.has(tag.id)
								? tag.color || '#00A3E0'
								: 'transparent'}; color: {cardTagIds.has(tag.id)
								? '#0A121F'
								: tag.color ||
									'#00A3E0'}; border-color: {tag.color ||
								'#00A3E0'};"
							onclick={() => toggleTag(tag.id)}
						>
							{tag.name}
						</button>
					{/each}
					{#if !showTagManager}
						{#if showTagInput}
							<div class="flex gap-1 items-center">
								<input
									type="text"
									class="bg-dark border border-light/20 rounded-lg px-2 py-1 text-sm text-white w-24 focus:outline-none focus:border-primary"
									placeholder="Tag name"
									bind:value={newTagName}
									onkeydown={(e) =>
										e.key === "Enter" && createTag()}
								/>
								<button
									type="button"
									class="text-primary text-sm font-bold hover:text-primary/80"
									onclick={createTag}
								>
									Add
								</button>
								<button
									type="button"
									class="text-light/40 text-sm hover:text-light"
									onclick={() => {
										showTagInput = false;
										newTagName = "";
									}}
								>
									Cancel
								</button>
							</div>
						{:else}
							<button
								type="button"
								class="rounded-lg px-2 py-1 text-sm text-light/50 hover:text-light border border-dashed border-light/20 hover:border-light/40 transition-colors"
								onclick={() => (showTagInput = true)}
							>
								+ New tag
							</button>
						{/if}
					{/if}
				</div>
			</div>

			<!-- Assignee, Due Date, Priority Row -->
			<div class="grid grid-cols-3 gap-4">
				<AssigneePicker
					label="Assignee"
					value={assigneeId}
					{members}
					onchange={(id) => (assigneeId = id)}
				/>

				<Input type="date" label="Due Date" bind:value={dueDate} />

				<Select
					label="Priority"
					bind:value={priority}
					placeholder=""
					options={[
						{ value: "low", label: "Low" },
						{ value: "medium", label: "Medium" },
						{ value: "high", label: "High" },
						{ value: "urgent", label: "Urgent" },
					]}
				/>
			</div>

			<div>
				<div class="flex items-center justify-between mb-3">
					<span class="px-3 font-bold font-body text-body text-white"
						>Checklist</span
					>
					{#if checklist.length > 0}
						<span class="text-xs text-light/50"
							>{completedCount}/{checklist.length}</span
						>
					{/if}
				</div>

				{#if checklist.length > 0}
					<div
						class="mb-3 h-1.5 bg-light/10 rounded-full overflow-hidden"
					>
						<div
							class="h-full bg-success transition-all duration-300"
							style="width: {progress}%"
						></div>
					</div>
				{/if}

				{#if isLoading}
					<div class="text-light/50 text-sm py-2">Loading...</div>
				{:else}
					<div class="space-y-2 mb-3">
						{#each checklist as item}
							<div class="flex items-center gap-3 group">
								<button
									class="w-5 h-5 rounded border flex items-center justify-center transition-colors
										{item.completed
										? 'bg-success border-success'
										: 'border-light/30 hover:border-light/50'}"
									onclick={() => toggleItem(item)}
								>
									{#if item.completed}
										<svg
											class="w-3 h-3 text-white"
											viewBox="0 0 24 24"
											fill="none"
											stroke="currentColor"
											stroke-width="3"
										>
											<polyline points="20,6 9,17 4,12" />
										</svg>
									{/if}
								</button>
								<span
									class="flex-1 text-sm {item.completed
										? 'line-through text-light/40'
										: 'text-light'}"
								>
									{item.title}
								</span>
								<button
									type="button"
									class="opacity-0 group-hover:opacity-100 p-1 text-light/40 hover:text-error transition-all"
									onclick={() => deleteItem(item.id)}
									aria-label="Delete item"
								>
									<Icon name="close" size={16} />
								</button>
							</div>
						{/each}
					</div>

					<div class="flex gap-2 items-end">
						<Input
							placeholder="Add an item..."
							bind:value={newItemTitle}
							onkeydown={(e) =>
								e.key === "Enter" && handleAddItem()}
						/>
						<Button
							size="md"
							onclick={handleAddItem}
							disabled={!newItemTitle.trim()}
						>
							Add
						</Button>
					</div>
				{/if}
			</div>

			<!-- Comments Section -->
			{#if mode === "edit"}
				<div>
					<span
						class="px-3 font-bold font-body text-body text-white mb-3 block"
						>Comments</span
					>
					<div class="space-y-3 mb-3 max-h-48 overflow-y-auto">
						{#each comments as comment}
							<div class="flex gap-3">
								<div
									class="w-8 h-8 rounded-full bg-primary/20 flex-shrink-0 flex items-center justify-center text-xs text-primary"
								>
									{(comment.profiles?.full_name ||
										comment.profiles?.email ||
										"?")[0].toUpperCase()}
								</div>
								<div class="flex-1 min-w-0">
									<div class="flex items-center gap-2">
										<span
											class="text-sm font-medium text-light"
										>
											{comment.profiles?.full_name ||
												comment.profiles?.email ||
												"Unknown"}
										</span>
										<span class="text-xs text-light/40"
											>{formatDate(
												comment.created_at,
											)}</span
										>
									</div>
									<p class="text-sm text-light/70 mt-0.5">
										{comment.content}
									</p>
								</div>
							</div>
						{/each}
						{#if comments.length === 0}
							<p class="text-sm text-light/40 text-center py-2">
								No comments yet
							</p>
						{/if}
					</div>
					<div class="flex gap-2 items-end">
						<Input
							placeholder="Add a comment..."
							bind:value={newComment}
							onkeydown={(e) =>
								e.key === "Enter" && handleAddComment()}
						/>
						<Button
							size="md"
							onclick={handleAddComment}
							disabled={!newComment.trim()}
						>
							Send
						</Button>
					</div>
				</div>
			{/if}

			<div
				class="flex items-center justify-between pt-3 border-t border-light/10"
			>
				{#if mode === "edit"}
					<Button variant="danger" onclick={handleDelete}>
						Delete Card
					</Button>
				{:else}
					<div></div>
				{/if}
				<div class="flex gap-2">
					<Button variant="tertiary" onclick={onClose}>Cancel</Button>
					<Button
						onclick={handleSave}
						loading={isSaving}
						disabled={!title.trim()}
					>
						{mode === "create" ? "Add Card" : "Save Changes"}
					</Button>
				</div>
			</div>
		</div>
	{/if}
</Modal>
