package templates

import (
	"backend/internal/auth"
	"backend/internal/db/sqlc"
	"backend/internal/web/ui"
	"strconv"
	"strings"
	"time"
)

// tablosGreeting returns a time-appropriate greeting prefix.
func tablosGreeting() string {
	h := time.Now().Hour()
	switch {
	case h < 12:
		return "Bonjour"
	case h < 18:
		return "Bon après-midi"
	default:
		return "Bonsoir"
	}
}

// tablosDisplayName returns the best available display name for a user.
// auth.User has no FirstName field, so we use the email prefix.
func tablosDisplayName(user *auth.User) string {
	prefix, _, _ := strings.Cut(user.Email, "@")
	if prefix == "" {
		return user.Email
	}
	return prefix
}

// TablosDashboard renders the root authenticated dashboard with sidebar AppLayout.
// Shows a project-card grid (or empty state) for the user's tablos.
templ TablosDashboard(user *auth.User, csrfToken string, activePath string, tablos []sqlc.Tablo, cards []TabloCardView, pageTitle string, breadcrumb []BreadcrumbItem) {
	@AppLayout("Tablos — Xtablo", user, csrfToken, activePath, tablos, pageTitle, breadcrumb, nil) {
		<div class="home-layout">
			<!-- Main content column -->
			<div class="home-main">
				<!-- Greeting -->
				<div class="home-date-line">{ time.Now().Format("Monday, 2 January 2006") }</div>
				<h1 class="home-greeting">{ tablosGreeting() }, { tablosDisplayName(user) } !</h1>
				<!-- Action pills row -->
				<div class="action-pills-row">
					<button
						type="button"
						class="action-pill primary-pill"
						hx-get="/tablos/new"
						hx-target="#create-form-slot"
						hx-swap="innerHTML"
					>
						<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><line x1="12" y1="5" x2="12" y2="19"></line><line x1="5" y1="12" x2="19" y2="12"></line></svg>
						Nouveau projet
					</button>
					<button type="button" class="action-pill" disabled>
						<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m3 17 2 2 4-4"></path><path d="m3 7 2 2 4-4"></path><path d="M13 6h8"></path><path d="M13 12h8"></path><path d="M13 18h8"></path></svg>
						Nouvelle tâche
					</button>
					<button type="button" class="action-pill" disabled>
						<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"></path><circle cx="9" cy="7" r="4"></circle><line x1="19" y1="8" x2="19" y2="14"></line><line x1="22" y1="11" x2="16" y2="11"></line></svg>
						Inviter un membre
					</button>
					<button type="button" class="action-pill" disabled>
						<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M7.9 20A9 9 0 1 0 4 16.1L2 22Z"></path></svg>
						Envoyer un message
					</button>
				</div>
				<div id="create-form-slot"></div>
				<!-- My Projects section -->
				<div class="section-header">
					<span class="section-title">Mes Projets</span>
					<div style="display:flex;align-items:center;gap:12px">
						<!-- View toggle grid/list -->
						<div class="view-toggle">
							<button type="button" class="view-btn active" data-view-btn="grid" onclick="setTablosView('grid')" aria-label="Vue en grille">
								<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect width="7" height="7" x="3" y="3" rx="1"></rect><rect width="7" height="7" x="14" y="3" rx="1"></rect><rect width="7" height="7" x="3" y="14" rx="1"></rect><rect width="7" height="7" x="14" y="14" rx="1"></rect></svg>
							</button>
							<button type="button" class="view-btn" data-view-btn="list" onclick="setTablosView('list')" aria-label="Vue en liste">
								<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12h.01"></path><path d="M3 18h.01"></path><path d="M3 6h.01"></path><path d="M8 12h13"></path><path d="M8 18h13"></path><path d="M8 6h13"></path></svg>
							</button>
						</div>
						<a href="/" class="see-all">Voir tout</a>
					</div>
				</div>
				<!-- Filter pills -->
				<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:16px">
					<button type="button" class="filter-pill active" data-filter-btn="tous" onclick="filterTablos('tous')">Tous</button>
					<button type="button" class="filter-pill" data-filter-btn="active" onclick="filterTablos('active')">Actif</button>
					<button type="button" class="filter-pill" data-filter-btn="archived" onclick="filterTablos('archived')">Archivé</button>
				</div>
				<!-- Grid view -->
				<div id="tablos-grid" class="card-grid">
					if len(cards) == 0 {
						@TablosEmptyState()
					} else {
						for _, card := range cards {
							@TabloProjectCard(card, csrfToken)
						}
					}
				</div>
				<!-- List view (hidden by default) -->
				<div id="tablos-table" class="hidden" style="background:#fff;border:1px solid var(--color-border-default);border-radius:12px;overflow:hidden">
					<table class="projects-table">
						<thead>
							<tr>
								<th>Projet</th>
								<th>Statut</th>
								<th>Créé le</th>
								<th>Progression</th>
								<th style="width:48px"></th>
							</tr>
						</thead>
						<tbody>
							for _, card := range cards {
								@TabloListRow(card, csrfToken)
							}
						</tbody>
					</table>
				</div>
				<!-- My Tasks section (stub) -->
				<div style="margin-top:32px">
					<div class="section-header">
						<span class="section-title">Mes Tâches</span>
					</div>
					<p style="font-size:.875rem;color:var(--color-text-muted);font-style:italic">Les tâches apparaîtront ici.</p>
				</div>
			</div>
			<!-- Contacts panel (stub) -->
			<div class="contacts-panel">
				<h2 style="font-size:.875rem;font-weight:600;color:var(--color-text-primary);margin:0 0 12px">Contacts</h2>
				<p style="font-size:.8125rem;color:var(--color-text-muted)">Vos contacts apparaîtront ici.</p>
			</div>
		</div>
		<script>
		function setTablosView(v) {
		  document.getElementById('tablos-grid').classList.toggle('hidden', v === 'list');
		  document.getElementById('tablos-table').classList.toggle('hidden', v === 'grid');
		  document.querySelectorAll('[data-view-btn]').forEach(function(b) {
		    b.classList.toggle('active', b.dataset.viewBtn === v);
		  });
		}
		function filterTablos(s) {
		  document.querySelectorAll('#tablos-grid article').forEach(function(el) {
		    el.style.display = (s === 'tous' || el.dataset.displayStatus === s) ? '' : 'none';
		  });
		  document.querySelectorAll('#tablos-table tbody tr').forEach(function(el) {
		    el.style.display = (s === 'tous' || el.dataset.displayStatus === s) ? '' : 'none';
		  });
		  document.querySelectorAll('[data-filter-btn]').forEach(function(b) {
		    b.classList.toggle('active', b.dataset.filterBtn === s);
		  });
		}
		document.getElementById('tablos-grid').addEventListener('click', function(e) {
		  var a = e.target.closest('article[data-href]');
		  if (a && !e.target.closest('.tablo-delete-zone')) window.location = a.dataset.href;
		});
		document.getElementById('tablos-table').addEventListener('click', function(e) {
		  var r = e.target.closest('tr[data-href]');
		  if (r && !e.target.closest('.tablo-delete-zone')) window.location = r.dataset.href;
		});
		</script>
	}
}

// TablosEmptyState renders the empty-state copy when a user has no tablos.
// Copy strings are locked by UI-SPEC Copywriting Contract.
// Uses ui.EmptyState for consistent styling across the app (Phase 13).
templ TablosEmptyState() {
	@ui.EmptyState(ui.EmptyStateProps{
		Title:       "No tablos yet",
		Description: "Create your first tablo to get started.",
		Action: ui.Button(ui.ButtonProps{
			Label:   "New tablo",
			Variant: ui.ButtonVariantDefault,
			Tone:    ui.ButtonToneSolid,
			Size:    ui.SizeMD,
			Type:    "button",
			Attrs: templ.Attributes{
				"hx-get":    "/tablos/new",
				"hx-target": "#create-form-slot",
				"hx-swap":   "innerHTML",
			},
		}),
	})
}

// TabloProjectCard renders a single tablo as a card in the grid view.
// Guards color rendering against null pgtype.Text values (Pitfall 6).
// Uses .Time accessor on pgtype.Timestamptz (Pitfall 6).
templ TabloProjectCard(card TabloCardView, csrfToken string) {
	<article
		id={ "tablo-" + card.Tablo.ID.String() }
		class="project-card"
		data-display-status={ card.Tablo.Status }
		data-href={ "/tablos/" + card.Tablo.ID.String() }
	>
		<!-- Card header: color circle + title + badge + delete -->
		<div class="card-header">
			if card.Tablo.Color.Valid && card.Tablo.Color.String != "" {
				<span class="card-color-circle" style={ "background:" + card.Tablo.Color.String }></span>
			} else {
				<span class="card-color-circle" style="background:#9ca3af"></span>
			}
			<span class="card-title">{ card.Tablo.Title }</span>
			if card.Tablo.Status == "archived" {
				<span class="badge-archived">Archivé</span>
			} else {
				<span class="badge-active">Actif</span>
			}
			<div class="tablo-delete-zone" style="flex-shrink:0;margin-left:4px" onclick="event.stopPropagation()">
				@ui.IconButton(ui.IconButtonProps{
					Label:   "Delete tablo",
					Icon:    "trash",
					Variant: ui.IconButtonVariantDanger,
					Tone:    ui.IconButtonToneGhost,
					Type:    "button",
					Attrs: templ.Attributes{
						"hx-get":    "/tablos/" + card.Tablo.ID.String() + "/delete-confirm",
						"hx-target": "closest .tablo-delete-zone",
						"hx-swap":   "outerHTML",
					},
				})
			</div>
		</div>
		<!-- Meta: date + task count -->
		<div class="card-meta">Créé le { card.Tablo.CreatedAt.Time.Format("2 Jan 2006") } · { strconv.Itoa(card.TotalTasks) } tâches</div>
		<!-- Progress bar -->
		<div class="progress-bar-wrap" style="height:4px;background:var(--color-surface-muted);border-radius:9999px;overflow:hidden;margin-bottom:8px">
			<div class="progress-bar-fill" style={ "height:100%;background:var(--color-brand-primary);width:" + strconv.Itoa(card.Progress) + "%" }></div>
		</div>
		<div style="display:flex;justify-content:space-between;font-size:.75rem;color:var(--color-text-muted)">
			<span>{ strconv.Itoa(card.Progress) }% terminé</span>
			<span>{ strconv.Itoa(card.DoneTasks) }/{ strconv.Itoa(card.TotalTasks) } fait</span>
		</div>
	</article>
}

// TabloListRow renders one table row for the list view.
templ TabloListRow(card TabloCardView, csrfToken string) {
	<tr
		data-display-status={ card.Tablo.Status }
		data-href={ "/tablos/" + card.Tablo.ID.String() }
	>
		<!-- Projet: color circle + title -->
		<td>
			<div class="proj-name-cell">
				if card.Tablo.Color.Valid && card.Tablo.Color.String != "" {
					<span class="card-color-circle" style={ "background:" + card.Tablo.Color.String }></span>
				} else {
					<span class="card-color-circle" style="background:#9ca3af"></span>
				}
				<span style="font-weight:500;color:var(--color-text-primary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap">{ card.Tablo.Title }</span>
			</div>
		</td>
		<!-- Statut -->
		<td>
			if card.Tablo.Status == "archived" {
				<span class="badge-archived">Archivé</span>
			} else {
				<span class="badge-active">Actif</span>
			}
		</td>
		<!-- Créé le -->
		<td style="white-space:nowrap;color:var(--color-text-secondary)">
			{ card.Tablo.CreatedAt.Time.Format("2 Jan 2006") }
		</td>
		<!-- Progression -->
		<td>
			<div class="progress-with-label">
				<div class="progress-bar-wrap">
					<div style={ "height:100%;background:var(--color-brand-primary);border-radius:9999px;width:" + strconv.Itoa(card.Progress) + "%" }></div>
				</div>
				<span class="progress-pct">{ strconv.Itoa(card.Progress) }%</span>
			</div>
		</td>
		<!-- Actions -->
		<td style="text-align:right">
			<div class="tablo-delete-zone" style="display:inline-flex" onclick="event.stopPropagation()">
				@ui.IconButton(ui.IconButtonProps{
					Label:   "Delete tablo",
					Icon:    "trash",
					Variant: ui.IconButtonVariantDanger,
					Tone:    ui.IconButtonToneGhost,
					Type:    "button",
					Attrs: templ.Attributes{
						"hx-get":    "/tablos/" + card.Tablo.ID.String() + "/delete-confirm",
						"hx-target": "closest .tablo-delete-zone",
						"hx-swap":   "outerHTML",
					},
				})
			</div>
		</td>
	</tr>
}

// TabloCard renders a single tablo as a ui.Card on the dashboard.
// Guards description and color rendering against null pgtype.Text values (Pitfall 6).
// Delegates delete-zone rendering to TabloDeleteButtonFragment (single source of truth).
templ TabloCard(card TabloCardView, csrfToken string) {
	<div id={ "tablo-" + card.Tablo.ID.String() }>
		@ui.Card(ui.CardProps{Body: tabloCardBody(card, csrfToken)})
	</div>
}

templ tabloCardBody(card TabloCardView, csrfToken string) {
	<div class="flex items-start justify-between">
		<div>
			<div class="flex flex-wrap items-center gap-2">
				<h2 class="text-xl font-semibold leading-snug">{ card.Tablo.Title }</h2>
				@DiscussionUnreadBadge(card.DiscussionUnreadCount)
			</div>
			if card.Tablo.Description.Valid && card.Tablo.Description.String != "" {
				<p class="mt-2 text-base text-slate-600">{ card.Tablo.Description.String }</p>
			}
			if card.Tablo.Color.Valid && card.Tablo.Color.String != "" {
				<div class="mt-2 flex items-center gap-2">
					<span
						class="inline-block w-2.5 h-2.5 rounded-full"
						style={ "background-color: " + card.Tablo.Color.String }
					></span>
					<span class="text-sm text-slate-500">{ card.Tablo.Color.String }</span>
				</div>
			}
		</div>
		@TabloDeleteButtonFragment(card.Tablo, csrfToken)
	</div>
	<div class="mt-4">
		<a href={ templ.SafeURL("/tablos/" + card.Tablo.ID.String()) } class="text-sm font-medium text-blue-600 hover:underline">View</a>
	</div>
}

templ DiscussionUnreadBadge(count int64) {
	if count > 0 {
		<span class="inline-flex min-w-6 items-center justify-center rounded-full border border-blue-200 bg-slate-50 px-2 py-0.5 text-xs font-semibold leading-none text-blue-700" aria-label={ DiscussionUnreadAriaLabel(count) }>{ DiscussionUnreadDisplay(count) }</span>
	}
}

// TabloCreateFormFragment renders the inline create form loaded into #create-form-slot
// via HTMX. Falls back to a plain POST /tablos for non-JS paths.
// UI-SPEC §2 Interaction Contract — GET /tablos/new + POST /tablos.
templ TabloCreateFormFragment(form TabloCreateForm, errs TabloCreateErrors, csrfToken string) {
	<form
		id="create-form"
		method="POST"
		action="/tablos"
		hx-post="/tablos"
		hx-target="#create-form-slot"
		hx-swap="innerHTML"
		class="mb-6 space-y-4 rounded border border-slate-200 bg-slate-50 p-6"
	>
		@ui.CSRFField(csrfToken)
		@GeneralError(errs.General)
		<h2 class="text-xl font-semibold leading-snug">Create a tablo</h2>
		<div>
			<label for="title" class="block text-sm font-medium text-slate-700">Title</label>
			<input
				id="title"
				type="text"
				name="title"
				value={ form.Title }
				required
				class="mt-1 block w-full rounded border border-slate-300 px-3 py-2 text-sm placeholder-slate-400 focus:border-slate-500 focus:outline-none"
				placeholder="My tablo"
			/>
			@FieldError(errs.Title)
		</div>
		<div>
			<label for="description" class="block text-sm font-medium text-slate-700">Description <span class="text-slate-400">(optional)</span></label>
			<textarea
				id="description"
				name="description"
				rows="3"
				class="mt-1 block w-full rounded border border-slate-300 px-3 py-2 text-sm placeholder-slate-400 focus:border-slate-500 focus:outline-none"
				placeholder="What is this tablo for?"
			>{ form.Description }</textarea>
		</div>
		<div>
			<label for="color" class="block text-sm font-medium text-slate-700">Color <span class="text-slate-400">(optional)</span></label>
			<input
				id="color"
				type="text"
				name="color"
				value={ form.Color }
				class="mt-1 block w-full rounded border border-slate-300 px-3 py-2 text-sm placeholder-slate-400 focus:border-slate-500 focus:outline-none"
				placeholder="#6366f1"
			/>
			@FieldError(errs.Color)
		</div>
		<div class="flex items-center gap-3">
			@ui.Button(ui.ButtonProps{
				Label:   "Create tablo",
				Variant: ui.ButtonVariantDefault,
				Tone:    ui.ButtonToneSolid,
				Size:    ui.SizeMD,
				Type:    "submit",
			})
			<a href="/" class="text-sm text-slate-600 hover:underline">Cancel</a>
		</div>
	</form>
}

// TabloCardWithOOBFormClear renders a TabloCard as the primary swap target
// AND an OOB element that clears #create-form-slot in the same response.
// The OOB div MUST be a top-level sibling of TabloCard — NOT nested (Pitfall 5).
// HTMX applies the primary swap (HX-Retarget: #tablos-list, afterbegin) AND
// the OOB swap (#create-form-slot → empty) from a single response.
templ TabloCardWithOOBFormClear(tablo sqlc.Tablo, csrfToken string) {
	@TabloCard(TabloCardFromTablo(tablo), csrfToken)
	<div id="create-form-slot" hx-swap-oob="true"></div>
}

// TabloDetailPage renders the full detail page for a single tablo.
// Tabs: Overview / Tasks / Files / Discussion / Events. activeTab selects the initially rendered tab content.
// files and tasks are pre-fetched slices for the active tab (may be nil for inactive tabs).
// activePath and sidebarTablos drive the AppLayout sidebar.
// UI-SPEC §3 Interaction Contract — GET /tablos/{id}.
// D-07: signature includes activeTab string param; D-08: tab bar links carry hx-push-url.
templ TabloDetailPage(user *auth.User, csrfToken string, activePath string, sidebarTablos []sqlc.Tablo, tablo sqlc.Tablo, tasks []sqlc.Task, etapes []sqlc.Etape, counts EtapeTaskCounts, filter EtapeFilter, files []sqlc.TabloFile, events EventsCalendar, discussion DiscussionTabData, activeTab string, pageTitle string, breadcrumb []BreadcrumbItem) {
	@AppLayout("Tablos — Xtablo", user, csrfToken, activePath, sidebarTablos, pageTitle, breadcrumb, nil) {
		<div class="tablo-detail-page">
			<header class="tablo-detail-header">
				<div class="tablo-detail-title-row">
					if tablo.Color.Valid && tablo.Color.String != "" {
						<div class="tablo-detail-avatar" style={ "background:" + tablo.Color.String }>
							if len(tablo.Title) > 0 {
								{ string([]rune(tablo.Title)[0:1]) }
							}
						</div>
					} else {
						<div class="tablo-detail-avatar">
							if len(tablo.Title) > 0 {
								{ string([]rune(tablo.Title)[0:1]) }
							}
						</div>
					}
					<div class="tablo-title-zone">
						@TabloTitleDisplay(tablo, csrfToken)
					</div>
					<div class="tablo-delete-zone">
						@ui.IconButton(ui.IconButtonProps{
							Label:   "Delete tablo",
							Icon:    "trash",
							Variant: ui.IconButtonVariantDanger,
							Tone:    ui.IconButtonToneGhost,
							Type:    "button",
							Attrs: templ.Attributes{
								"hx-get":    "/tablos/" + tablo.ID.String() + "/delete-confirm",
								"hx-target": "closest .tablo-delete-zone",
								"hx-swap":   "outerHTML",
							},
						})
					</div>
				</div>
				<div class="tablo-metadata-row">
					<span class="tablo-meta-segment">
						<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect width="18" height="18" x="3" y="4" rx="2" ry="2"></rect><line x1="16" x2="16" y1="2" y2="6"></line><line x1="8" x2="8" y1="2" y2="6"></line><line x1="3" x2="21" y1="10" y2="10"></line></svg>
						<span>Created</span>
						<span>{ tablo.CreatedAt.Time.Format("Jan 2, 2006") }</span>
					</span>
					<span class="tablo-meta-segment">
						@ui.Badge(ui.BadgeProps{Label: "In progress", Variant: ui.BadgeVariantPrimary})
					</span>
					<span class="tablo-meta-segment tablo-meta-progress">
						<div class="project-progress-track" style="min-width:120px">
							<div class="tablo-progress-bar" style="width:0%"></div>
						</div>
						<strong>0%</strong>
					</span>
				</div>
			</header>
			<nav class="tablo-tab-bar">
				<a
					href={ templ.SafeURL("/tablos/" + tablo.ID.String()) }
					hx-get={ "/tablos/" + tablo.ID.String() }
					hx-target="#tab-content"
					hx-swap="innerHTML"
					hx-push-url={ "/tablos/" + tablo.ID.String() }
					if activeTab == "overview" || activeTab == "" {
						class="tab-nav-item is-active"
					} else {
						class="tab-nav-item"
					}
				>
					<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="7" height="9" x="3" y="3" rx="1"></rect><rect width="7" height="5" x="14" y="3" rx="1"></rect><rect width="7" height="9" x="14" y="12" rx="1"></rect><rect width="7" height="5" x="3" y="16" rx="1"></rect></svg>
					Vue d&apos;ensemble
				</a>
				<a
					href={ templ.SafeURL("/tablos/" + tablo.ID.String() + "/tasks") }
					hx-get={ "/tablos/" + tablo.ID.String() + "/tasks" }
					hx-target="#tab-content"
					hx-swap="innerHTML"
					hx-push-url={ "/tablos/" + tablo.ID.String() + "/tasks" }
					if activeTab == "tasks" {
						class="tab-nav-item is-active"
					} else {
						class="tab-nav-item"
					}
				>
					<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m3 17 2 2 4-4"></path><path d="m3 7 2 2 4-4"></path><path d="M13 6h8"></path><path d="M13 12h8"></path><path d="M13 18h8"></path></svg>
					Tâches
				</a>
				<a
					href={ templ.SafeURL("/tablos/" + tablo.ID.String() + "/files") }
					hx-get={ "/tablos/" + tablo.ID.String() + "/files" }
					hx-target="#tab-content"
					hx-swap="innerHTML"
					hx-push-url={ "/tablos/" + tablo.ID.String() + "/files" }
					if activeTab == "files" {
						class="tab-nav-item is-active"
					} else {
						class="tab-nav-item"
					}
				>
					<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 20h16a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.93a2 2 0 0 1-1.66-.9l-.82-1.2A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13c0 1.1.9 2 2 2Z"></path></svg>
					Fichiers
				</a>
				<a
					href={ templ.SafeURL("/tablos/" + tablo.ID.String() + "/discussion") }
					hx-get={ "/tablos/" + tablo.ID.String() + "/discussion" }
					hx-target="#tab-content"
					hx-swap="innerHTML"
					hx-push-url={ "/tablos/" + tablo.ID.String() + "/discussion" }
					if activeTab == "discussion" {
						class="tab-nav-item is-active"
					} else {
						class="tab-nav-item"
					}
				>
					<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M7.9 20A9 9 0 1 0 4 16.1L2 22Z"></path></svg>
					Discussion
				</a>
				<a
					href={ templ.SafeURL("/tablos/" + tablo.ID.String() + "/events") }
					hx-get={ "/tablos/" + tablo.ID.String() + "/events" }
					hx-target="#tab-content"
					hx-swap="innerHTML"
					hx-push-url={ "/tablos/" + tablo.ID.String() + "/events" }
					if activeTab == "events" {
						class="tab-nav-item is-active"
					} else {
						class="tab-nav-item"
					}
				>
					<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="18" x="3" y="4" rx="2" ry="2"></rect><line x1="16" x2="16" y1="2" y2="6"></line><line x1="8" x2="8" y1="2" y2="6"></line><line x1="3" x2="21" y1="10" y2="10"></line></svg>
					Événements
				</a>
			</nav>
			<!-- Tab content area — HTMX tab switches target this div -->
			<div id="tab-content" class="pt-6 pb-8">
				if activeTab == "tasks" {
					@TasksTabFragment(tablo, tasks, etapes, counts, filter, csrfToken)
				} else if activeTab == "files" {
					@FilesTabFragment(tablo, files, csrfToken)
				} else if activeTab == "events" {
					@EventsTabFragment(tablo, events, csrfToken)
				} else if activeTab == "discussion" {
					@DiscussionTabFragment(tablo, discussion, DiscussionForm{}, DiscussionErrors{}, csrfToken)
				} else {
					@TabloOverviewTabFragment(tablo, csrfToken)
				}
			</div>
		</div>
	}
}

// TabloOverviewTabFragment renders the overview tab content — description inline-edit zone.
// Returned as a standalone fragment for HTMX tab-switch responses.
// Description zone relocated here from the persistent header (Phase 16 Plan 02).
templ TabloOverviewTabFragment(tablo sqlc.Tablo, csrfToken string) {
	<div class="overview-tab">
		<div class="tablo-desc-zone">
			@TabloDescDisplay(tablo, csrfToken)
		</div>
	</div>
}

// TasksTabFragment wraps the KanbanBoard for use as a standalone HTMX tab fragment.
// Returned by TabloTasksTabHandler on HX-Request == "true".
// Lives in tablos.templ (tablo-level concern) per plan D-07.
templ TasksTabFragment(tablo sqlc.Tablo, tasks []sqlc.Task, etapes []sqlc.Etape, counts EtapeTaskCounts, filter EtapeFilter, csrfToken string) {
	<div id="tasks-tab">
		@KanbanBoard(tablo.ID, csrfToken, tasks, filter, etapes)
	</div>
}

// TabloTitleDisplay renders the tablo title as a clickable element that swaps
// to the edit form on click. The outermost element carries class tablo-title-zone
// so hx-target="closest .tablo-title-zone" + hx-swap="outerHTML" round-trips cleanly.
// UI-SPEC §4 Interaction Contract — title inline-edit display state.
templ TabloTitleDisplay(tablo sqlc.Tablo, csrfToken string) {
	<h1
		class="tablo-title-zone text-xl md:text-3xl font-bold text-foreground cursor-pointer transition-colors"
		hx-get={ "/tablos/" + tablo.ID.String() + "/edit-title" }
		hx-target="closest .tablo-title-zone"
		hx-swap="outerHTML"
		role="button"
		aria-label="Edit title"
	>{ tablo.Title }</h1>
}

// TabloTitleEditFragment renders the inline title edit form. Carries class
// tablo-title-zone on the form element so outerHTML round-trips work correctly.
// Includes hidden description field (current value) + hidden _zone="title" for
// TabloUpdateHandler to know which display fragment to render on success.
// UI-SPEC §4 Interaction Contract — title inline-edit edit state.
templ TabloTitleEditFragment(tablo sqlc.Tablo, errs TabloUpdateErrors, csrfToken string) {
	<form
		class="tablo-title-zone space-y-3"
		method="POST"
		action={ templ.SafeURL("/tablos/" + tablo.ID.String()) }
		hx-post={ "/tablos/" + tablo.ID.String() }
		hx-target="closest .tablo-title-zone"
		hx-swap="outerHTML"
	>
		@ui.CSRFField(csrfToken)
		<input type="hidden" name="_zone" value="title"/>
		<input type="hidden" name="description" value={ tablo.Description.String }/>
		<div>
			<label for="title" class="block text-sm font-medium text-slate-700">Title</label>
			<input
				id="title"
				type="text"
				name="title"
				value={ tablo.Title }
				required
				class="mt-1 block w-full rounded border border-slate-300 px-3 py-2 text-sm placeholder-slate-400 focus:border-slate-500 focus:outline-none"
			/>
			@FieldError(errs.Title)
		</div>
		<div class="flex items-center gap-3">
			@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/" + tablo.ID.String() + "/show-title",
					"hx-target": "closest .tablo-title-zone",
					"hx-swap":   "outerHTML",
				},
			})
		</div>
	</form>
}

// TabloDescDisplay renders the tablo description as a clickable element that
// swaps to the edit form on click. Carries class tablo-desc-zone on the outermost
// element for clean outerHTML round-trips.
// UI-SPEC §4 Interaction Contract — description inline-edit display state.
templ TabloDescDisplay(tablo sqlc.Tablo, csrfToken string) {
	<div
		class="tablo-desc-zone mt-4 cursor-pointer hover:text-slate-600"
		hx-get={ "/tablos/" + tablo.ID.String() + "/edit-desc" }
		hx-target="closest .tablo-desc-zone"
		hx-swap="outerHTML"
		role="button"
		aria-label="Edit description"
	>
		if tablo.Description.Valid && tablo.Description.String != "" {
			<p class="text-base text-slate-600">{ tablo.Description.String }</p>
		} else {
			<p class="text-sm text-slate-400 italic">Add a description</p>
		}
	</div>
}

// TabloDescEditFragment renders the inline description edit form. Carries class
// tablo-desc-zone on the form element so outerHTML round-trips work correctly.
// Includes hidden title field (current value) + hidden _zone="desc" for
// TabloUpdateHandler to know which display fragment to render on success.
// UI-SPEC §4 Interaction Contract — description inline-edit edit state.
templ TabloDescEditFragment(tablo sqlc.Tablo, errs TabloUpdateErrors, csrfToken string) {
	<form
		class="tablo-desc-zone mt-4 space-y-3"
		method="POST"
		action={ templ.SafeURL("/tablos/" + tablo.ID.String()) }
		hx-post={ "/tablos/" + tablo.ID.String() }
		hx-target="closest .tablo-desc-zone"
		hx-swap="outerHTML"
	>
		@ui.CSRFField(csrfToken)
		<input type="hidden" name="_zone" value="desc"/>
		<input type="hidden" name="title" value={ tablo.Title }/>
		<div>
			<label for="description" class="block text-sm font-medium text-slate-700">Description <span class="text-slate-400">(optional)</span></label>
			<textarea
				id="description"
				name="description"
				rows="3"
				class="mt-1 block w-full rounded border border-slate-300 px-3 py-2 text-sm placeholder-slate-400 focus:border-slate-500 focus:outline-none"
			>{ tablo.Description.String }</textarea>
			@FieldError(errs.Description)
		</div>
		<div class="flex items-center gap-3">
			@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/" + tablo.ID.String() + "/show-desc",
					"hx-target": "closest .tablo-desc-zone",
					"hx-swap":   "outerHTML",
				},
			})
		</div>
	</form>
}

// TabloDeleteButtonFragment renders the delete trigger button wrapped in a
// .tablo-delete-zone div. This is the canonical single source of truth for the
// delete zone shape — TabloCard delegates to this component (no duplication).
// UI-SPEC §5 Interaction Contract — delete display state.
templ TabloDeleteButtonFragment(tablo sqlc.Tablo, csrfToken string) {
	<div class="tablo-delete-zone">
		@ui.Button(ui.ButtonProps{
			Label:   "Delete",
			Variant: ui.ButtonVariantDanger,
			Tone:    ui.ButtonToneSoft,
			Size:    ui.SizeMD,
			Type:    "button",
			Attrs: templ.Attributes{
				"hx-get":    "/tablos/" + tablo.ID.String() + "/delete-confirm",
				"hx-target": "closest .tablo-delete-zone",
				"hx-swap":   "outerHTML",
				"aria-label": "Delete tablo",
			},
		})
	</div>
}

// TabloDeleteConfirmFragment renders the inline confirmation dialog that appears
// when the user clicks Delete. Carries class tablo-delete-zone for outerHTML
// round-trips. "Yes, delete" submits the DELETE action; "Keep tablo" restores
// the original Delete button via TabloDeleteCancelHandler.
// UI-SPEC §5 Interaction Contract — delete confirmation state.
templ TabloDeleteConfirmFragment(tablo sqlc.Tablo, csrfToken string) {
	<div class="tablo-delete-zone space-y-3">
		<p class="text-base font-semibold text-slate-800">Delete tablo?</p>
		<p class="text-sm text-slate-600">This cannot be undone.</p>
		<div class="flex items-center gap-3">
			<form
				method="POST"
				action={ templ.SafeURL("/tablos/" + tablo.ID.String() + "/delete") }
				hx-post={ "/tablos/" + tablo.ID.String() + "/delete" }
				hx-target="closest .tablo-delete-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 tablo",
					},
				})
			</form>
			@ui.Button(ui.ButtonProps{
				Label:   "Keep tablo",
				Variant: ui.ButtonVariantNeutral,
				Tone:    ui.ButtonToneSoft,
				Size:    ui.SizeMD,
				Type:    "button",
				Attrs: templ.Attributes{
					"hx-get":    "/tablos/" + tablo.ID.String() + "/delete-cancel",
					"hx-target": "closest .tablo-delete-zone",
					"hx-swap":   "outerHTML",
					"aria-label": "Keep tablo",
				},
			})
		</div>
	</div>
}

// TabloNotFoundPage renders a 404 page for tablos that don't exist or are not
// accessible by the current user (D-04: 404 not 403 to avoid existence leakage).
// activePath and sidebarTablos drive the AppLayout sidebar (pass "" and empty slice for not-found).
// UI-SPEC Copywriting Contract: "Not found" + "This tablo doesn't exist or you don't have access."
templ TabloNotFoundPage(user *auth.User, csrfToken string, activePath string, sidebarTablos []sqlc.Tablo) {
	@AppLayout("Not found", user, csrfToken, activePath, sidebarTablos, "Not found", nil, nil) {
		<div class="py-16 text-center">
			<h1 class="text-2xl font-semibold leading-snug text-slate-800">Not found</h1>
			<p class="mt-2 text-base text-slate-600">This tablo doesn&#39;t exist or you don&#39;t have access.</p>
			<div class="mt-6">
				<a href="/" class="text-sm font-medium text-blue-600 hover:underline">Back to tablos</a>
			</div>
		</div>
	}
}
