package templates

import (
	"backend/internal/db/sqlc"
	"backend/internal/web/ui"
	"github.com/google/uuid"
	"strconv"
)

// groupTasksByStatus groups a flat task slice into a map keyed by TaskStatus.
// Returns a map; missing statuses return nil (empty) slices.
func groupTasksByStatus(tasks []sqlc.Task) map[sqlc.TaskStatus][]sqlc.Task {
	result := make(map[sqlc.TaskStatus][]sqlc.Task, len(TaskColumns))
	for _, t := range tasks {
		result[t.Status] = append(result[t.Status], t)
	}
	return result
}

// KanbanBoard renders the outer board container with 4 columns and a hidden
// reorder form. Used by TabloDetailPage below the tablo header section.
// UI-SPEC §1 and D-08.
templ KanbanBoard(tabloID uuid.UUID, csrfToken string, tasks []sqlc.Task, filter EtapeFilter) {
	{{ grouped := groupTasksByStatus(tasks) }}
	<div id="kanban-board" class="flex gap-4 overflow-x-auto pb-4">
		<form
			id="reorder-form"
			method="POST"
			action={ templ.SafeURL("/tablos/" + tabloID.String() + "/tasks/reorder" + filter.QueryParam()) }
			hx-post={ "/tablos/" + tabloID.String() + "/tasks/reorder" + filter.QueryParam() }
			hx-target="#kanban-board"
			hx-swap="outerHTML"
			class="hidden"
		>
			@ui.CSRFField(csrfToken)
		</form>
		for _, status := range TaskColumns {
			@KanbanColumn(tabloID, status, grouped[status], csrfToken, filter)
		}
		<script>
			(function() {
				function initSortable(root) {
					var cols = root.querySelectorAll ? root.querySelectorAll(".sortable-column") : [];
					if (cols.length === 0) {
						cols = document.querySelectorAll(".sortable-column");
					}
					cols.forEach(function(col) {
						if (col._sortableInit) { return; }
						col._sortableInit = true;
						new Sortable(col, {
							group: "kanban",
							animation: 150,
							handle: ".task-drag-handle",
							draggable: ".task-card-zone",
							ghostClass: "bg-slate-100",
							chosenClass: "opacity-50",
							onEnd: function() {
								var form = document.getElementById("reorder-form");
								form.querySelectorAll("input[name=task_id],input[name=task_col]").forEach(function(el) { el.remove(); });
								document.querySelectorAll(".sortable-column").forEach(function(c) {
									c.querySelectorAll(".task-card").forEach(function(card) {
										var inp = document.createElement("input");
										inp.type = "hidden"; inp.name = "task_id"; inp.value = card.dataset.taskId;
										form.appendChild(inp);
										var colInp = document.createElement("input");
										colInp.type = "hidden"; colInp.name = "task_col"; colInp.value = c.dataset.status;
										form.appendChild(colInp);
									});
								});
								htmx.trigger(form, "submit");
							}
						});
					});
				}

				function updateBadges() {
					document.querySelectorAll(".sortable-column").forEach(function(col) {
						var status = col.dataset.status;
						var count = col.querySelectorAll(".task-card").length;
						var wrapper = document.getElementById("task-count-badge-" + status);
						if (wrapper) {
							var inner = wrapper.querySelector("span") || wrapper;
							inner.textContent = String(count);
						}
					});
				}

				// Initial page load — runs after all defer scripts (htmx + sortable) have executed.
				document.addEventListener("DOMContentLoaded", function() {
					initSortable(document.body);
					updateBadges();
				});

				// After any HTMX swap — re-init new columns and refresh badge counts.
				document.addEventListener("htmx:afterSettle", function() {
					initSortable(document.body);
					updateBadges();
				});
			})();
		</script>
	</div>
}

// KanbanColumn renders a single kanban column: header, task list, and add-task slot.
// UI-SPEC §1 and §2.
templ KanbanColumn(tabloID uuid.UUID, status sqlc.TaskStatus, tasks []sqlc.Task, csrfToken string, filter EtapeFilter) {
	<div class="flex-shrink-0 w-72">
		<div class="bg-slate-100 rounded px-3 py-2 mb-2 flex items-center justify-between">
			<h3 class="text-sm font-semibold text-slate-700">{ TaskColumnLabels[status] }</h3>
			<span id={ "task-count-badge-" + string(status) }>
				@ui.Badge(ui.BadgeProps{Label: strconv.Itoa(len(tasks)), Variant: ui.BadgeVariantInfo})
			</span>
		</div>
		<div
			class="sortable-column min-h-16 space-y-2"
			data-status={ string(status) }
			id={ "column-" + string(status) }
			aria-label={ TaskColumnLabels[status] + " column" }
		>
			if len(tasks) == 0 {
				<p class="text-sm text-slate-400 italic px-2 py-1">No tasks yet</p>
			}
			for _, task := range tasks {
				@TaskCard(tabloID, task, csrfToken)
			}
		</div>
		<div id={ "add-task-slot-" + string(status) }>
			@AddTaskTrigger(tabloID, status, csrfToken, filter)
		</div>
	</div>
}

// TaskCard renders a single task card. The outer wrapper carries class "task-card-zone"
// and id="task-{task.ID}" so HTMX outerHTML swaps round-trip cleanly.
// UI-SPEC §4 and D-08.
templ TaskCard(tabloID uuid.UUID, task sqlc.Task, csrfToken string) {
	<div class="task-card-zone" id={ "task-" + task.ID.String() }>
		<div
			class="task-card bg-white rounded border border-slate-200 px-3 py-2 shadow-sm"
			data-task-id={ task.ID.String() }
		>
			<div class="flex items-start justify-between gap-2">
				<div class="flex items-start gap-2 flex-1 min-w-0">
					<div class="task-drag-handle cursor-grab text-slate-400 select-none mt-0.5" aria-hidden="true">⠿</div>
					<div
						class="flex-1 min-w-0 cursor-pointer"
						hx-get={ "/tablos/" + tabloID.String() + "/tasks/" + task.ID.String() + "/edit" }
						hx-target="closest .task-card-zone"
						hx-swap="outerHTML"
						role="button"
						aria-label={ "Edit task: " + task.Title }
					>
						<p class="text-sm text-slate-800 break-words">{ task.Title }</p>
					</div>
				</div>
				<button
					type="button"
					class="ui-button ui-button-soft ui-button-danger ui-button-md flex-shrink-0 text-xs"
					hx-get={ "/tablos/" + tabloID.String() + "/tasks/" + task.ID.String() + "/delete-confirm" }
					hx-target="closest .task-card-zone"
					hx-swap="outerHTML"
					aria-label={ "Delete task: " + task.Title }
				>Delete</button>
			</div>
		</div>
	</div>
}

// TaskEditFragment renders the inline edit form for an existing task.
// The outer wrapper carries class="task-card-zone" id="task-{task.ID}" so
// HTMX outerHTML swaps round-trip cleanly with TaskCard (TASK-03).
// UI-SPEC §3.
templ TaskEditFragment(tabloID uuid.UUID, task sqlc.Task, etapes []sqlc.Etape, form TaskUpdateForm, errs TaskUpdateErrors, csrfToken string) {
	<div class="task-card-zone" id={ "task-" + task.ID.String() }>
		{{ selectedEtapeID := taskEtapeIDString(task.EtapeID) }}
		<form
			method="POST"
			action={ templ.SafeURL("/tablos/" + tabloID.String() + "/tasks/" + task.ID.String()) }
			hx-post={ "/tablos/" + tabloID.String() + "/tasks/" + task.ID.String() }
			hx-target="closest .task-card-zone"
			hx-swap="outerHTML"
			class="bg-white rounded border border-slate-200 p-3 shadow-sm space-y-2"
		>
			@ui.CSRFField(csrfToken)
			<div>
				<input
					type="text"
					name="title"
					value={ form.Title }
					maxlength="255"
					required
					placeholder="Task title"
					class="block w-full rounded border border-slate-300 px-2 py-1 text-sm placeholder-slate-400 focus:border-slate-500 focus:outline-none"
				/>
				@FieldError(errs.Title)
			</div>
			<div>
				<label class="block text-xs font-medium text-slate-600 mb-1">Etape</label>
				<select
					name="etape_id"
					class="block w-full rounded border border-slate-300 px-2 py-1 text-sm focus:border-slate-500 focus:outline-none"
				>
					if selectedEtapeID == "" {
						<option value="" selected>No etape</option>
					} else {
						<option value="">No etape</option>
					}
					for _, etape := range etapes {
						if selectedEtapeID == etape.ID.String() {
							<option value={ etape.ID.String() } selected>{ etape.Title }</option>
						} else {
							<option value={ etape.ID.String() }>{ etape.Title }</option>
						}
					}
				</select>
			</div>
			<div>
				<textarea
					name="description"
					rows="3"
					placeholder="Description (optional)"
					class="block w-full rounded border border-slate-300 px-2 py-1 text-sm placeholder-slate-400 focus:border-slate-500 focus:outline-none"
				>{ form.Description }</textarea>
			</div>
			if errs.General != "" {
				@FieldError(errs.General)
			}
			<div class="flex items-center gap-2">
				@ui.Button(ui.ButtonProps{
					Label:   "Save changes",
					Variant: ui.ButtonVariantDefault,
					Tone:    ui.ButtonToneSolid,
					Size:    ui.SizeMD,
					Type:    "submit",
				})
				@ui.Button(ui.ButtonProps{
					Label:   "Discard changes",
					Variant: ui.ButtonVariantNeutral,
					Tone:    ui.ButtonToneSoft,
					Size:    ui.SizeMD,
					Type:    "button",
					Attrs: templ.Attributes{
						"hx-get":    "/tablos/" + tabloID.String() + "/tasks/" + task.ID.String() + "/show",
						"hx-target": "closest .task-card-zone",
						"hx-swap":   "outerHTML",
					},
				})
			</div>
		</form>
	</div>
}

// TaskCreateFormFragment renders the inline create form shown when a user clicks
// "+ Add task". Targets #column-{status} for HTMX beforeend swap on submit.
// UI-SPEC §2.
templ TaskCreateFormFragment(tabloID uuid.UUID, status sqlc.TaskStatus, form TaskCreateForm, errs TaskCreateErrors, csrfToken string, filter EtapeFilter, etapes []sqlc.Etape) {
	<form
		method="POST"
		action={ templ.SafeURL("/tablos/" + tabloID.String() + "/tasks") }
		hx-post={ "/tablos/" + tabloID.String() + "/tasks" }
		hx-target={ "#column-" + string(status) }
		hx-swap="beforeend"
		class="bg-white rounded border border-slate-200 p-3 shadow-sm space-y-2"
	>
		<input type="hidden" name="status" value={ string(status) }/>
		@ui.CSRFField(csrfToken)
		<div>
			<input
				type="text"
				name="title"
				value={ form.Title }
				maxlength="255"
				required
				placeholder="Task title"
				class="block w-full rounded border border-slate-300 px-2 py-1 text-sm placeholder-slate-400 focus:border-slate-500 focus:outline-none"
			/>
			@FieldError(errs.Title)
		</div>
		<div>
			<label class="block text-xs font-medium text-slate-600 mb-1">Etape</label>
			<select
				name="etape_id"
				class="block w-full rounded border border-slate-300 px-2 py-1 text-sm focus:border-slate-500 focus:outline-none"
			>
				if form.EtapeID == "" {
					<option value="" selected>No etape</option>
				} else {
					<option value="">No etape</option>
				}
				for _, etape := range etapes {
					if form.EtapeID == etape.ID.String() {
						<option value={ etape.ID.String() } selected>{ etape.Title }</option>
					} else {
						<option value={ etape.ID.String() }>{ etape.Title }</option>
					}
				}
			</select>
		</div>
		<div class="flex items-center gap-2">
			@ui.Button(ui.ButtonProps{
				Label:   "Save",
				Variant: ui.ButtonVariantDefault,
				Tone:    ui.ButtonToneSolid,
				Size:    ui.SizeMD,
				Type:    "submit",
			})
			@ui.Button(ui.ButtonProps{
				Label:   "Discard",
				Variant: ui.ButtonVariantNeutral,
				Tone:    ui.ButtonToneSoft,
				Size:    ui.SizeMD,
				Type:    "button",
				Attrs: templ.Attributes{
					"hx-get":    "/tablos/" + tabloID.String() + "/tasks/cancel-new?status=" + string(status) + filter.QuerySuffix(),
					"hx-target": "#add-task-slot-" + string(status),
					"hx-swap":   "innerHTML",
				},
			})
		</div>
	</form>
}

// TaskDeleteConfirmFragment renders the delete confirmation dialog for a task.
// Carries class "task-card-zone" so outerHTML round-trips work correctly.
// UI-SPEC §5.
templ TaskDeleteConfirmFragment(tabloID uuid.UUID, task sqlc.Task, csrfToken string) {
	<div class="task-card-zone" id={ "task-" + task.ID.String() }>
		<div class="bg-white rounded border border-slate-200 p-3 shadow-sm space-y-2">
			<p class="text-sm font-semibold text-slate-800">Delete task?</p>
			<p class="text-xs text-slate-600">This cannot be undone.</p>
			<div class="flex items-center gap-2">
				<form
					method="POST"
					action={ templ.SafeURL("/tablos/" + tabloID.String() + "/tasks/" + task.ID.String() + "/delete") }
					hx-post={ "/tablos/" + tabloID.String() + "/tasks/" + task.ID.String() + "/delete" }
					hx-target="closest .task-card-zone"
					hx-swap="outerHTML"
				>
					@ui.CSRFField(csrfToken)
					@ui.Button(ui.ButtonProps{
						Label:   "Yes, delete",
						Variant: ui.ButtonVariantDanger,
						Tone:    ui.ButtonToneSolid,
						Size:    ui.SizeMD,
						Type:    "submit",
						Attrs: templ.Attributes{
							"aria-label": "Confirm delete task",
						},
					})
				</form>
				@ui.Button(ui.ButtonProps{
					Label:   "Keep task",
					Variant: ui.ButtonVariantNeutral,
					Tone:    ui.ButtonToneSoft,
					Size:    ui.SizeMD,
					Type:    "button",
					Attrs: templ.Attributes{
						"hx-get":    "/tablos/" + tabloID.String() + "/tasks/" + task.ID.String() + "/show",
						"hx-target": "closest .task-card-zone",
						"hx-swap":   "outerHTML",
						"aria-label": "Keep task",
					},
				})
			</div>
		</div>
	</div>
}

// AddTaskTrigger renders the "+ Add task" button that expands to TaskCreateFormFragment.
// Targets #add-task-slot-{status} for innerHTML replacement.
// UI-SPEC §2.
templ AddTaskTrigger(tabloID uuid.UUID, status sqlc.TaskStatus, csrfToken string, filter EtapeFilter) {
	<button
		type="button"
		class="ui-button ui-button-soft ui-button-neutral ui-button-md w-full text-left text-sm mt-2"
		hx-get={ "/tablos/" + tabloID.String() + "/tasks/new?status=" + string(status) + filter.QuerySuffix() }
		hx-target={ "#add-task-slot-" + string(status) }
		hx-swap="innerHTML"
	>+ Add task</button>
}

// TaskCardGone renders an empty zone div with the task's id so HTMX outerHTML
// swap removes the card from the DOM after a successful delete (TASK-06).
templ TaskCardGone(taskID uuid.UUID, tabloID uuid.UUID, csrfToken string, filter EtapeFilter, etapes []sqlc.Etape, counts EtapeTaskCounts) {
	<div id={ "task-" + taskID.String() } class="task-card-zone"></div>
	@EtapeStrip(tabloID, etapes, counts, filter, csrfToken, true)
}

// TaskCardOOB renders a new TaskCard AND an OOB swap that resets the add-task
// slot to AddTaskTrigger. Used by TaskCreateHandler to perform both operations
// in a single HTMX response.
// D-08/UI-SPEC §2: OOB swap resets #add-task-slot-{status} after create.
templ TaskCardOOB(status sqlc.TaskStatus, task sqlc.Task, tabloID uuid.UUID, csrfToken string, filter EtapeFilter, etapes []sqlc.Etape, counts EtapeTaskCounts) {
	@TaskCard(tabloID, task, csrfToken)
	<div hx-swap-oob={ "innerHTML:#add-task-slot-" + string(status) }>
		@AddTaskTrigger(tabloID, status, csrfToken, filter)
	</div>
	@EtapeStrip(tabloID, etapes, counts, filter, csrfToken, true)
}
