"use client";

import { useReducer, useEffect, useRef } from "react";
import { useRouter } from "next/navigation";
import {
  getWaterEntries,
  getWaterDisplaySummary,
  createWaterIrrigator,
  createWaterHeadgate,
  type AdminHeadgate as Headgate,
  type AdminIrrigator as WaterUser,
  type AdminEntry as WaterEntry,
  type WaterDisplaySummary,
  type WaterDisplayHeadgate,
  type AlertLogEntry,
} from "@/actions/water-log/admin";
import { logoutWaterAdmin } from "@/actions/water-log/field";

/* ── Props ────────────────────────────────────────────────────────── */

type Props = {
  initialSummary: WaterDisplaySummary | null;
  initialHeadgates: Headgate[];
  initialUsers: WaterUser[];
  initialAlertLog: AlertLogEntry[];
};

/* ── i18n ─────────────────────────────────────────────────────────── */

const LABELS = {
  en: {
    title: "Water Log Admin",
    loggedInAs: "Tuxedo Field Operations",
    logout: "Sign out",
    recentEntries: "Recent Entries",
    noEntries: "No entries yet",
    noMatches: "No matches",
    when: "When",
    user: "User",
    headgate: "Headgate",
    measurement: "Measurement",
    via: "Via",
    field: "Field",
    admin: "Admin",
    exportCSV: "Export CSV",
    clearFilters: "Clear",
    save: "Save",
    saveShort: "+",
    loadMore: "Load more",
    displaySummary: "Display Summary",
    todayCount: "Entries today",
    todayTotalSuffix: "total",
    lastUpdate: "Last update",
    refreshIn: "Refresh in",
    noHeadgates: "No active headgates",
    noLatest: "No readings",
    noEntriesToday: "No entries today",
    headgates: "Headgates",
    users: "Users",
    alerts: "Alert Log",
    addHeadgate: "Add headgate",
    addUser: "Add user",
    edit: "Edit",
    cancel: "Cancel",
    name: "Name",
    unit: "Unit",
    active: "Active",
    inactive: "Inactive",
    role: "Role",
    language: "Language",
    pin: "PIN",
    newPinFor: "New PIN for",
    writeThisDown: "Write this down — it will not be shown again.",
    dismiss: "Dismiss",
    saving: "Saving…",
    filterAll: "All headgates",
    filterAllVia: "All via",
    noUsers: "No users yet",
    noAlerts: "No alerts triggered yet.",
    time: "Time",
    threshold: "Threshold",
    reading: "Reading",
    alertHigh: "High ↑",
    alertLow: "Low ↓",
    minutesAgo: "m ago",
    hoursAgo: "h ago",
    justNow: "Just now",
    never: "Never",
  },
  es: {
    title: "Administración del Registro de Agua",
    loggedInAs: "Operaciones de Campo Tuxedo",
    logout: "Salir",
    recentEntries: "Entradas recientes",
    noEntries: "Sin entradas aún",
    noMatches: "Sin resultados",
    when: "Fecha",
    user: "Usuario",
    headgate: "Compuerta",
    measurement: "Medición",
    via: "Vía",
    field: "Campo",
    admin: "Admin",
    exportCSV: "Exportar CSV",
    clearFilters: "Limpiar",
    save: "Guardar",
    saveShort: "+",
    loadMore: "Cargar más",
    displaySummary: "Resumen de pantalla",
    todayCount: "Entradas hoy",
    todayTotalSuffix: "total",
    lastUpdate: "Última actualización",
    refreshIn: "Refresca en",
    noHeadgates: "Sin compuertas activas",
    noLatest: "Sin lecturas",
    noEntriesToday: "Sin entradas hoy",
    headgates: "Compuertas",
    users: "Usuarios",
    alerts: "Registro de alertas",
    addHeadgate: "Agregar compuerta",
    addUser: "Agregar usuario",
    edit: "Editar",
    cancel: "Cancelar",
    name: "Nombre",
    unit: "Unidad",
    active: "Activo",
    inactive: "Inactivo",
    role: "Rol",
    language: "Idioma",
    pin: "PIN",
    newPinFor: "Nuevo PIN para",
    writeThisDown: "Anótalo — no se mostrará de nuevo.",
    dismiss: "Cerrar",
    saving: "Guardando…",
    filterAll: "Todas las compuertas",
    filterAllVia: "Todos los medios",
    noUsers: "Sin usuarios aún",
    noAlerts: "Sin alertas aún.",
    time: "Hora",
    threshold: "Umbral",
    reading: "Lectura",
    alertHigh: "Alta ↑",
    alertLow: "Baja ↓",
    minutesAgo: "m",
    hoursAgo: "h",
    justNow: "Ahora",
    never: "Nunca",
  },
} as const;

type Labels = (typeof LABELS)["en" | "es"];

function detectInitialLang(): "en" | "es" {
  if (typeof document === "undefined") return "es"; // server snapshot fallback; client useEffect adjusts
  const cookie = document.cookie.match(/wl_lang=(en|es)/)?.[1];
  if (cookie === "en" || cookie === "es") return cookie;
  if (typeof navigator !== "undefined") {
    const lang = navigator.language?.toLowerCase() ?? "";
    if (lang.startsWith("en")) return "en";
  }
  return "es"; // default for this predominantly-Spanish audience
}

const UNIT_OPTIONS = ["CFS", "GPM", "gal", "ac-in", "ac-ft"];

/* ── State ────────────────────────────────────────────────────────── */

type State = {
  lang: "en" | "es";
  displaySummary: WaterDisplaySummary | null;
  refreshCountdown: number;
  entries: WaterEntry[];
  entriesPage: number; // 0 = first 50, 1 = next 50, ...
  entriesHasMore: boolean;
  entriesLoading: boolean;
  users: WaterUser[];
  headgates: Headgate[];
  alertLog: AlertLogEntry[];
  filterDateFrom: string;
  filterDateTo: string;
  filterHeadgate: string;
  filterVia: string;
  showHeadgates: boolean;
  showUsers: boolean;
  showEntries: boolean;
  showAlerts: boolean;
  showAddHg: boolean;
  showAddUser: boolean;
  newPin: { name: string; pin: string } | null;
  newUserName: string;
  newUserLang: "en" | "es";
  savingUser: boolean;
  newUserError: string | null;
  newHgName: string;
  newHgUnit: string;
  savingHg: boolean;
  newHgError: string | null;
};

type Action =
  | { type: "SET_LANG"; lang: "en" | "es" }
  | { type: "SET_DISPLAY_SUMMARY"; summary: WaterDisplaySummary | null }
  | { type: "DECREMENT_COUNTDOWN" }
  | { type: "RESET_COUNTDOWN"; value: number }
  | { type: "SET_ENTRIES"; entries: WaterEntry[]; append?: boolean }
  | { type: "SET_ENTRIES_PAGE"; page: number }
  | { type: "SET_ENTRIES_HAS_MORE"; value: boolean }
  | { type: "SET_ENTRIES_LOADING"; value: boolean }
  | { type: "SET_USERS"; users: WaterUser[] }
  | { type: "SET_HEADGATES"; headgates: Headgate[] }
  | { type: "SET_ALERT_LOG"; alertLog: AlertLogEntry[] }
  | {
      type: "SET_FILTER";
      field: "filterDateFrom" | "filterDateTo" | "filterHeadgate" | "filterVia";
      value: string;
    }
  | { type: "CLEAR_FILTERS" }
  | {
      type: "TOGGLE";
      key:
        | "showHeadgates"
        | "showUsers"
        | "showEntries"
        | "showAlerts"
        | "showAddHg"
        | "showAddUser";
    }
  | { type: "SET_NEW_PIN"; value: { name: string; pin: string } | null }
  | { type: "SET_NEW_USER_NAME"; value: string }
  | { type: "SET_NEW_USER_LANG"; value: "en" | "es" }
  | { type: "SET_SAVING_USER"; value: boolean }
  | { type: "SET_NEW_USER_ERROR"; value: string | null }
  | { type: "SET_NEW_HG_NAME"; value: string }
  | { type: "SET_NEW_HG_UNIT"; value: string }
  | { type: "SET_SAVING_HG"; value: boolean }
  | { type: "SET_NEW_HG_ERROR"; value: string | null };

function reducer(state: State, action: Action): State {
  switch (action.type) {
    case "SET_LANG":
      return { ...state, lang: action.lang };
    case "SET_DISPLAY_SUMMARY":
      return { ...state, displaySummary: action.summary };
    case "DECREMENT_COUNTDOWN":
      return { ...state, refreshCountdown: Math.max(state.refreshCountdown - 1, 0) };
    case "RESET_COUNTDOWN":
      return { ...state, refreshCountdown: action.value };
    case "SET_ENTRIES":
      return {
        ...state,
        entries: action.append ? [...state.entries, ...action.entries] : action.entries,
      };
    case "SET_ENTRIES_PAGE":
      return { ...state, entriesPage: action.page };
    case "SET_ENTRIES_HAS_MORE":
      return { ...state, entriesHasMore: action.value };
    case "SET_ENTRIES_LOADING":
      return { ...state, entriesLoading: action.value };
    case "SET_USERS":
      return { ...state, users: action.users };
    case "SET_HEADGATES":
      return { ...state, headgates: action.headgates };
    case "SET_ALERT_LOG":
      return { ...state, alertLog: action.alertLog };
    case "SET_FILTER":
      return { ...state, [action.field]: action.value };
    case "CLEAR_FILTERS":
      return {
        ...state,
        filterDateFrom: "",
        filterDateTo: "",
        filterHeadgate: "",
        filterVia: "",
      };
    case "TOGGLE":
      return { ...state, [action.key]: !state[action.key] };
    case "SET_NEW_PIN":
      return { ...state, newPin: action.value };
    case "SET_NEW_USER_NAME":
      return { ...state, newUserName: action.value };
    case "SET_NEW_USER_LANG":
      return { ...state, newUserLang: action.value };
    case "SET_SAVING_USER":
      return { ...state, savingUser: action.value };
    case "SET_NEW_USER_ERROR":
      return { ...state, newUserError: action.value };
    case "SET_NEW_HG_NAME":
      return { ...state, newHgName: action.value };
    case "SET_NEW_HG_UNIT":
      return { ...state, newHgUnit: action.value };
    case "SET_SAVING_HG":
      return { ...state, savingHg: action.value };
    case "SET_NEW_HG_ERROR":
      return { ...state, newHgError: action.value };
  }
}

const PAGE_SIZE = 50;
const REFRESH_SECONDS = 30;

function reducerInit(
  initialSummary: WaterDisplaySummary | null,
  initialHeadgates: Headgate[],
  initialUsers: WaterUser[],
  initialAlertLog: AlertLogEntry[],
): State {
  return {
    lang: "es",
    displaySummary: initialSummary,
    refreshCountdown: REFRESH_SECONDS,
    entries: [],
    entriesPage: -1, // -1 means "haven't loaded yet"; first load treats this as page 0
    entriesHasMore: true,
    entriesLoading: false,
    users: initialUsers,
    headgates: initialHeadgates,
    alertLog: initialAlertLog,
    filterDateFrom: "",
    filterDateTo: "",
    filterHeadgate: "",
    filterVia: "",
    showHeadgates: true,
    showUsers: true,
    showEntries: true,
    showAlerts: true,
    showAddHg: false,
    showAddUser: false,
    newPin: null,
    newUserName: "",
    newUserLang: "es",
    savingUser: false,
    newUserError: null,
    newHgName: "",
    newHgUnit: "CFS",
    savingHg: false,
    newHgError: null,
  };
}

/* ── Helpers ──────────────────────────────────────────────────────── */

const TUXEDO_BRAND_ID = "64294306-5f42-463d-a5e8-2ad6c81a96de";

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

function ageLabel(minutes_ago: number | null, t: Labels): string {
  if (minutes_ago === null) return t.never;
  if (minutes_ago < 2) return t.justNow;
  if (minutes_ago < 60) return `${minutes_ago}${t.minutesAgo}`;
  return `${Math.floor(minutes_ago / 60)}${t.hoursAgo}`;
}

function ageColor(minutes_ago: number | null): "ok" | "warn" | "down" {
  if (minutes_ago === null) return "down";
  if (minutes_ago > 60) return "warn";
  return "ok";
}

/* ── Subcomponents ────────────────────────────────────────────────── */

function AdminHeader({
  title,
  subtitle,
  lang,
  onChangeLang,
  onLogout,
  t,
}: {
  title: string;
  subtitle: string;
  lang: "en" | "es";
  onChangeLang: (l: "en" | "es") => void;
  onLogout: () => void;
  t: Labels;
}) {
  return (
    <header className="sticky top-0 z-20 bg-zinc-950/80 backdrop-blur ring-1 ring-zinc-800">
      <div className="mx-auto flex max-w-2xl items-center justify-between gap-3 px-4 py-3">
        <div className="min-w-0">
          <h1 className="truncate text-base font-bold tracking-tight text-zinc-50 sm:text-lg">
            {title}
          </h1>
          <p className="truncate text-xs text-zinc-500">{subtitle}</p>
        </div>
        <div className="flex shrink-0 items-center gap-2">
          <div className="flex overflow-hidden rounded-md ring-1 ring-zinc-800">
            <button
              type="button"
              onClick={() => onChangeLang("en")}
              aria-pressed={lang === "en"}
              className={`px-2 py-1 text-xs font-semibold uppercase tracking-wider transition-colors ${
                lang === "en"
                  ? "bg-zinc-100 text-zinc-900"
                  : "text-zinc-400 hover:bg-zinc-900 hover:text-zinc-200"
              }`}
            >
              EN
            </button>
            <button
              type="button"
              onClick={() => onChangeLang("es")}
              aria-pressed={lang === "es"}
              className={`px-2 py-1 text-xs font-semibold uppercase tracking-wider transition-colors ${
                lang === "es"
                  ? "bg-zinc-100 text-zinc-900"
                  : "text-zinc-400 hover:bg-zinc-900 hover:text-zinc-200"
              }`}
            >
              ES
            </button>
          </div>
          <button
            type="button"
            onClick={onLogout}
            className="rounded-md bg-zinc-100 px-3 py-2 text-sm font-semibold text-zinc-900 transition-colors hover:bg-white min-h-[40px]"
          >
            {t.logout}
          </button>
        </div>
      </div>
    </header>
  );
}

function SectionLabel({ children, count }: { children: React.ReactNode; count?: number }) {
  return (
    <div className="flex items-center gap-2">
      <h2 className="text-xs font-bold uppercase tracking-[0.18em] text-zinc-500">
        {children}
      </h2>
      {count !== undefined && (
        <span className="rounded-full bg-zinc-800 px-1.5 py-0.5 text-[10px] font-bold tabular-nums text-zinc-400">
          {count}
        </span>
      )}
    </div>
  );
}

function ToggleButton({
  open,
  onClick,
}: {
  open: boolean;
  onClick: () => void;
}) {
  return (
    <button
      type="button"
      onClick={onClick}
      aria-label={open ? "Collapse" : "Expand"}
      className="rounded-md p-1 text-zinc-500 transition-colors hover:bg-zinc-800 hover:text-zinc-200"
    >
      <svg
        viewBox="0 0 20 20"
        fill="currentColor"
        className={`h-4 w-4 transition-transform ${open ? "rotate-0" : "-rotate-90"}`}
      >
        <path
          fillRule="evenodd"
          d="M5.23 7.21a.75.75 0 011.06.02L10 11.06l3.71-3.83a.75.75 0 111.08 1.04l-4.25 4.39a.75.75 0 01-1.08 0L5.21 8.27a.75.75 0 01.02-1.06z"
          clipRule="evenodd"
        />
      </svg>
    </button>
  );
}

function HeadgateCard({ hg, t }: { hg: WaterDisplayHeadgate; t: Labels }) {
  const tone = ageColor(hg.minutes_ago);
  const pillClass =
    tone === "ok"
      ? "bg-green-900/30 text-green-400 ring-1 ring-inset ring-green-900/50"
      : tone === "warn"
        ? "bg-amber-900/30 text-amber-300 ring-1 ring-inset ring-amber-900/50"
        : "bg-zinc-800 text-zinc-500 ring-1 ring-inset ring-zinc-700";
  return (
    <div className="min-w-[160px] shrink-0 rounded-xl bg-zinc-900 p-4 ring-1 ring-zinc-800">
      <p className="truncate text-sm font-semibold text-zinc-100">{hg.name}</p>
      {hg.latest_entry ? (
        <>
          <p className="mt-2 text-2xl font-bold tabular-nums text-zinc-50">
            {hg.latest_entry.measurement}
            <span className="ml-1 text-xs font-medium text-zinc-500">{hg.unit}</span>
          </p>
          <p className="mt-0.5 truncate text-xs text-zinc-400">{hg.latest_entry.user_name}</p>
          <span
            className={`mt-2 inline-block rounded-full px-2 py-0.5 text-[10px] font-bold uppercase tracking-wider ${pillClass}`}
          >
            {ageLabel(hg.minutes_ago, t)}
          </span>
        </>
      ) : (
        <p className="mt-2 text-xs text-zinc-500">{t.noLatest}</p>
      )}
    </div>
  );
}

function DisplaySummarySection({
  displaySummary,
  refreshCountdown,
  t,
}: {
  displaySummary: WaterDisplaySummary | null;
  refreshCountdown: number;
  t: Labels;
}) {
  return (
    <section className="space-y-3">
      <div className="flex items-center justify-between">
        <SectionLabel>{t.displaySummary}</SectionLabel>
        <span className="text-[11px] font-semibold uppercase tracking-wider text-zinc-500 tabular-nums">
          {t.refreshIn} {refreshCountdown}s
        </span>
      </div>

      {displaySummary ? (
        <div className="rounded-2xl bg-zinc-900 p-5 ring-1 ring-zinc-800">
          {displaySummary.headgates.length === 0 ? (
            <p className="text-sm text-zinc-400">{t.noHeadgates}</p>
          ) : (
            <div className="-mx-1 flex snap-x snap-mandatory gap-2 overflow-x-auto px-1 pb-1">
              {displaySummary.headgates.map((hg) => (
                <div key={hg.id} className="snap-start">
                  <HeadgateCard hg={hg} t={t} />
                </div>
              ))}
            </div>
          )}

          <div className="mt-5 flex items-end justify-between border-t border-zinc-800 pt-4">
            <div>
              <p className="text-[11px] font-bold uppercase tracking-wider text-zinc-500">
                {t.todayCount}
              </p>
              <p className="mt-1 text-3xl font-bold tabular-nums text-zinc-50">
                {displaySummary.today_count}
                {displaySummary.today_count > 0 && (
                  <span className="ml-2 text-base font-medium tabular-nums text-zinc-500">
                    {displaySummary.today_total.toFixed(1)} {t.todayTotalSuffix}
                  </span>
                )}
              </p>
            </div>
            {displaySummary.recent_entries[0] && (
              <p className="text-right text-[11px] text-zinc-500">
                {t.lastUpdate}
                <br />
                <span className="font-semibold text-zinc-300">
                  {formatDateTime(displaySummary.recent_entries[0].logged_at)}
                </span>
              </p>
            )}
          </div>
        </div>
      ) : (
        <div className="rounded-2xl bg-zinc-900 p-5 ring-1 ring-zinc-800">
          <p className="text-sm text-zinc-400">{t.noEntriesToday}</p>
        </div>
      )}
    </section>
  );
}

function HeadgatesSection({
  headgates,
  showHeadgates,
  showAddHg,
  newHgName,
  newHgUnit,
  savingHg,
  newHgError,
  t,
  onToggleSection,
  onToggleAdd,
  onChangeName,
  onChangeUnit,
  onSubmit,
  onCancel,
  onEdit,
}: {
  headgates: Headgate[];
  showHeadgates: boolean;
  showAddHg: boolean;
  newHgName: string;
  newHgUnit: string;
  savingHg: boolean;
  newHgError: string | null;
  t: Labels;
  onToggleSection: () => void;
  onToggleAdd: () => void;
  onChangeName: (v: string) => void;
  onChangeUnit: (v: string) => void;
  onSubmit: (e: React.FormEvent) => void;
  onCancel: () => void;
  onEdit: (id: string) => void;
}) {
  return (
    <section className="rounded-2xl bg-zinc-900 p-5 ring-1 ring-zinc-800">
      <header className="mb-4 flex items-center justify-between">
        <SectionLabel count={headgates.length}>{t.headgates}</SectionLabel>
        <div className="flex items-center gap-1">
          <button
            type="button"
            onClick={onToggleAdd}
            aria-label={t.addHeadgate}
            className="rounded-md bg-zinc-100 px-2.5 py-1 text-xs font-bold text-zinc-900 transition-colors hover:bg-white"
          >
            +
          </button>
          <ToggleButton open={showHeadgates} onClick={onToggleSection} />
        </div>
      </header>

      {showAddHg && (
        <form
          onSubmit={onSubmit}
          className="mb-4 space-y-2 rounded-xl bg-zinc-950 p-3 ring-1 ring-zinc-800"
        >
          <input
            type="text"
            value={newHgName}
            onChange={(e) => onChangeName(e.target.value)}
            placeholder={t.name}
            required
            aria-label={t.name}
            className="w-full rounded-md border-0 bg-zinc-900 px-3 py-2 text-sm text-zinc-100 ring-1 ring-inset ring-zinc-700 placeholder:text-zinc-500 focus:outline-none focus:ring-2 focus:ring-zinc-400 min-h-[40px]"
          />
          <div className="flex gap-2">
            <select
              value={newHgUnit}
              onChange={(e) => onChangeUnit(e.target.value)}
              aria-label={t.unit}
              className="flex-1 rounded-md border-0 bg-zinc-900 px-3 py-2 text-sm text-zinc-100 ring-1 ring-inset ring-zinc-700 focus:outline-none focus:ring-2 focus:ring-zinc-400 min-h-[40px]"
            >
              {UNIT_OPTIONS.map((u) => (
                <option key={u} value={u}>
                  {u}
                </option>
              ))}
            </select>
            <button
              type="submit"
              disabled={savingHg}
              className="rounded-md bg-green-600 px-4 py-2 text-sm font-semibold text-white transition-colors hover:bg-green-500 disabled:opacity-50 min-h-[40px]"
            >
              {savingHg ? t.saving : t.saveShort}
            </button>
            <button
              type="button"
              onClick={onCancel}
              aria-label={t.cancel}
              className="rounded-md px-3 py-2 text-sm text-zinc-400 transition-colors hover:bg-zinc-800 hover:text-zinc-200 min-h-[40px]"
            >
              ×
            </button>
          </div>
        </form>
      )}
      {newHgError && (
        <div className="mb-3 rounded-md bg-red-900/30 px-3 py-2 text-xs text-red-300 ring-1 ring-inset ring-red-900/50">
          {newHgError}
        </div>
      )}

      {showHeadgates && (
        <ul className="divide-y divide-zinc-800/60">
          {headgates.length === 0 ? (
            <p className="py-3 text-sm text-zinc-500">{t.noHeadgates}</p>
          ) : (
            headgates.map((hg) => (
              <li
                key={hg.id}
                className="flex items-center justify-between gap-3 py-3 first:pt-0 last:pb-0"
              >
                <div className="flex min-w-0 items-center gap-3">
                  <span
                    className={`h-2 w-2 shrink-0 rounded-full ${
                      hg.active ? "bg-green-400" : "bg-zinc-600"
                    }`}
                    aria-hidden
                  />
                  <span className="truncate text-sm font-semibold text-zinc-100">
                    {hg.name}
                  </span>
                  <span className="rounded bg-zinc-800 px-1.5 py-0.5 text-[10px] font-bold uppercase tracking-wider text-zinc-400">
                    {hg.unit}
                  </span>
                </div>
                <button
                  type="button"
                  onClick={() => onEdit(hg.id)}
                  className="shrink-0 rounded-md px-3 py-1.5 text-xs font-semibold text-zinc-400 transition-colors hover:bg-zinc-800 hover:text-zinc-100"
                >
                  {t.edit}
                </button>
              </li>
            ))
          )}
        </ul>
      )}
    </section>
  );
}

function UsersSection({
  users,
  showUsers,
  showAddUser,
  newUserName,
  newUserLang,
  savingUser,
  newUserError,
  newPin,
  t,
  onToggleSection,
  onToggleAdd,
  onChangeName,
  onChangeLang,
  onSubmit,
  onCancel,
  onDismissPin,
  onEdit,
}: {
  users: WaterUser[];
  showUsers: boolean;
  showAddUser: boolean;
  newUserName: string;
  newUserLang: "en" | "es";
  savingUser: boolean;
  newUserError: string | null;
  newPin: { name: string; pin: string } | null;
  t: Labels;
  onToggleSection: () => void;
  onToggleAdd: () => void;
  onChangeName: (v: string) => void;
  onChangeLang: (v: "en" | "es") => void;
  onSubmit: (e: React.FormEvent) => void;
  onCancel: () => void;
  onDismissPin: () => void;
  onEdit: (id: string) => void;
}) {
  return (
    <section className="rounded-2xl bg-zinc-900 p-5 ring-1 ring-zinc-800">
      {newPin && (
        <div className="mb-4 rounded-xl bg-amber-900/30 p-4 ring-1 ring-inset ring-amber-700/50">
          <p className="text-[11px] font-bold uppercase tracking-wider text-amber-300">
            {t.newPinFor} {newPin.name}
          </p>
          <p className="mt-1 font-mono text-3xl font-bold tracking-[0.4em] text-amber-100">
            {newPin.pin}
          </p>
          <p className="mt-2 text-xs text-amber-200/80">{t.writeThisDown}</p>
          <button
            type="button"
            onClick={onDismissPin}
            className="mt-2 text-xs font-semibold text-amber-300 underline underline-offset-2 hover:text-amber-200"
          >
            {t.dismiss}
          </button>
        </div>
      )}

      <header className="mb-4 flex items-center justify-between">
        <SectionLabel count={users.length}>{t.users}</SectionLabel>
        <div className="flex items-center gap-1">
          <button
            type="button"
            onClick={onToggleAdd}
            aria-label={t.addUser}
            className="rounded-md bg-zinc-100 px-2.5 py-1 text-xs font-bold text-zinc-900 transition-colors hover:bg-white"
          >
            +
          </button>
          <ToggleButton open={showUsers} onClick={onToggleSection} />
        </div>
      </header>

      {showAddUser && (
        <form
          onSubmit={onSubmit}
          className="mb-4 space-y-2 rounded-xl bg-zinc-950 p-3 ring-1 ring-zinc-800"
        >
          <input
            type="text"
            value={newUserName}
            onChange={(e) => onChangeName(e.target.value)}
            placeholder={t.name}
            required
            aria-label={t.name}
            className="w-full rounded-md border-0 bg-zinc-900 px-3 py-2 text-sm text-zinc-100 ring-1 ring-inset ring-zinc-700 placeholder:text-zinc-500 focus:outline-none focus:ring-2 focus:ring-zinc-400 min-h-[40px]"
          />
          <div className="flex gap-2">
            <select
              value={newUserLang}
              onChange={(e) => onChangeLang(e.target.value as "en" | "es")}
              aria-label={t.language}
              className="rounded-md border-0 bg-zinc-900 px-3 py-2 text-sm text-zinc-100 ring-1 ring-inset ring-zinc-700 focus:outline-none focus:ring-2 focus:ring-zinc-400 min-h-[40px]"
            >
              <option value="en">EN</option>
              <option value="es">ES</option>
            </select>
            <button
              type="submit"
              disabled={savingUser}
              className="flex-1 rounded-md bg-green-600 px-4 py-2 text-sm font-semibold text-white transition-colors hover:bg-green-500 disabled:opacity-50 min-h-[40px]"
            >
              {savingUser ? t.saving : t.pin}
            </button>
            <button
              type="button"
              onClick={onCancel}
              aria-label={t.cancel}
              className="rounded-md px-3 py-2 text-sm text-zinc-400 transition-colors hover:bg-zinc-800 hover:text-zinc-200 min-h-[40px]"
            >
              ×
            </button>
          </div>
        </form>
      )}
      {newUserError && (
        <div className="mb-3 rounded-md bg-red-900/30 px-3 py-2 text-xs text-red-300 ring-1 ring-inset ring-red-900/50">
          {newUserError}
        </div>
      )}

      {showUsers && (
        <ul className="divide-y divide-zinc-800/60">
          {users.length === 0 ? (
            <p className="py-3 text-sm text-zinc-500">{t.noUsers}</p>
          ) : (
            users.map((u) => (
              <li
                key={u.id}
                className="flex items-center justify-between gap-3 py-3 first:pt-0 last:pb-0"
              >
                <div className="flex min-w-0 items-center gap-3">
                  <span
                    className={`h-2 w-2 shrink-0 rounded-full ${
                      u.active ? "bg-green-400" : "bg-zinc-600"
                    }`}
                    aria-hidden
                  />
                  <span className="truncate text-sm font-semibold text-zinc-100">
                    {u.name}
                  </span>
                  <span
                    className={`rounded px-1.5 py-0.5 text-[10px] font-bold uppercase tracking-wider ring-1 ring-inset ${
                      u.role === "water_admin"
                        ? "bg-blue-900/30 text-blue-300 ring-blue-900/50"
                        : "bg-zinc-800 text-zinc-400 ring-zinc-700"
                    }`}
                  >
                    {u.role === "water_admin" ? t.admin : t.field}
                  </span>
                </div>
                <button
                  type="button"
                  onClick={() => onEdit(u.id)}
                  className="shrink-0 rounded-md px-3 py-1.5 text-xs font-semibold text-zinc-400 transition-colors hover:bg-zinc-800 hover:text-zinc-100"
                >
                  {t.edit}
                </button>
              </li>
            ))
          )}
        </ul>
      )}
    </section>
  );
}

function EntriesSection({
  entries,
  entriesLoading,
  entriesHasMore,
  showEntries,
  filterDateFrom,
  filterDateTo,
  filterHeadgate,
  filterVia,
  headgateOptions,
  t,
  onToggleSection,
  onChangeFilter,
  onClearFilters,
  onLoadMore,
}: {
  entries: WaterEntry[];
  entriesLoading: boolean;
  entriesHasMore: boolean;
  showEntries: boolean;
  filterDateFrom: string;
  filterDateTo: string;
  filterHeadgate: string;
  filterVia: string;
  headgateOptions: { id: string; name: string }[];
  t: Labels;
  onToggleSection: () => void;
  onChangeFilter: (
    field: "filterDateFrom" | "filterDateTo" | "filterHeadgate" | "filterVia",
    value: string,
  ) => void;
  onClearFilters: () => void;
  onLoadMore: () => void;
}) {
  const filtersActive = filterDateFrom || filterDateTo || filterHeadgate || filterVia;

  return (
    <section className="rounded-2xl bg-zinc-900 p-5 ring-1 ring-zinc-800">
      <header className="mb-4 flex items-center justify-between">
        <SectionLabel count={entries.length}>{t.recentEntries}</SectionLabel>
        <ToggleButton open={showEntries} onClick={onToggleSection} />
      </header>

      {showEntries && (
        <>
          <div className="mb-3 flex flex-wrap gap-2">
            <input
              type="date"
              value={filterDateFrom}
              onChange={(e) => onChangeFilter("filterDateFrom", e.target.value)}
              aria-label={t.when}
              className="rounded-md border-0 bg-zinc-950 px-2 py-1.5 text-sm text-zinc-200 ring-1 ring-inset ring-zinc-700 focus:outline-none focus:ring-2 focus:ring-zinc-400 min-h-[36px]"
            />
            <input
              type="date"
              value={filterDateTo}
              onChange={(e) => onChangeFilter("filterDateTo", e.target.value)}
              aria-label={t.when}
              className="rounded-md border-0 bg-zinc-950 px-2 py-1.5 text-sm text-zinc-200 ring-1 ring-inset ring-zinc-700 focus:outline-none focus:ring-2 focus:ring-zinc-400 min-h-[36px]"
            />
            <select
              value={filterHeadgate}
              onChange={(e) => onChangeFilter("filterHeadgate", e.target.value)}
              aria-label={t.headgate}
              className="rounded-md border-0 bg-zinc-950 px-2 py-1.5 text-sm text-zinc-200 ring-1 ring-inset ring-zinc-700 focus:outline-none focus:ring-2 focus:ring-zinc-400 min-h-[36px]"
            >
              <option value="">{t.filterAll}</option>
              {headgateOptions.map((hg) => (
                <option key={hg.id} value={hg.id}>
                  {hg.name}
                </option>
              ))}
            </select>
            <select
              value={filterVia}
              onChange={(e) => onChangeFilter("filterVia", e.target.value)}
              aria-label={t.via}
              className="rounded-md border-0 bg-zinc-950 px-2 py-1.5 text-sm text-zinc-200 ring-1 ring-inset ring-zinc-700 focus:outline-none focus:ring-2 focus:ring-zinc-400 min-h-[36px]"
            >
              <option value="">{t.filterAllVia}</option>
              <option value="field">{t.field}</option>
              <option value="admin">{t.admin}</option>
            </select>
            {filtersActive && (
              <button
                type="button"
                onClick={onClearFilters}
                className="self-center text-xs font-semibold text-zinc-400 underline underline-offset-2 hover:text-zinc-200"
              >
                {t.clearFilters}
              </button>
            )}
          </div>

          <div className="-mx-5 overflow-x-auto px-5">
            <table className="w-full min-w-[480px] text-sm">
              <thead>
                <tr className="border-b border-zinc-800">
                  <th className="pb-2 pr-3 text-left text-[10px] font-bold uppercase tracking-wider text-zinc-500">
                    {t.when}
                  </th>
                  <th className="hidden pb-2 pr-3 text-left text-[10px] font-bold uppercase tracking-wider text-zinc-500 sm:table-cell">
                    {t.user}
                  </th>
                  <th className="pb-2 pr-3 text-left text-[10px] font-bold uppercase tracking-wider text-zinc-500">
                    {t.headgate}
                  </th>
                  <th className="pb-2 pr-3 text-right text-[10px] font-bold uppercase tracking-wider text-zinc-500">
                    {t.measurement}
                  </th>
                  <th className="pb-2 text-right text-[10px] font-bold uppercase tracking-wider text-zinc-500">
                    {t.via}
                  </th>
                </tr>
              </thead>
              <tbody>
                {entries.length === 0 ? (
                  <tr>
                    <td colSpan={5} className="py-6 text-center text-sm text-zinc-500">
                      {filtersActive ? t.noMatches : t.noEntries}
                    </td>
                  </tr>
                ) : (
                  entries.map((e) => (
                    <tr
                      key={e.id}
                      className="border-b border-zinc-800/50 last:border-0 hover:bg-zinc-800/30"
                    >
                      <td className="py-2.5 pr-3 text-xs tabular-nums text-zinc-400">
                        {formatDateTime(e.logged_at)}
                      </td>
                      <td className="hidden py-2.5 pr-3 text-xs text-zinc-300 sm:table-cell">
                        {e.user_name}
                      </td>
                      <td className="py-2.5 pr-3 text-xs text-zinc-300">{e.headgate_name}</td>
                      <td className="py-2.5 pr-3 text-right text-xs font-semibold tabular-nums text-zinc-100">
                        {e.measurement} {e.unit}
                      </td>
                      <td className="py-2.5 text-right">
                        <span
                          className={`inline-block rounded px-1.5 py-0.5 text-[10px] font-bold uppercase tracking-wider ring-1 ring-inset ${
                            e.submitted_via === "field"
                              ? "bg-blue-900/30 text-blue-300 ring-blue-900/50"
                              : "bg-zinc-800 text-zinc-400 ring-zinc-700"
                          }`}
                        >
                          {e.submitted_via === "field" ? t.field[0] : t.admin[0]}
                        </span>
                      </td>
                    </tr>
                  ))
                )}
              </tbody>
            </table>
          </div>

          {entriesHasMore && (
            <div className="mt-3 flex justify-center">
              <button
                type="button"
                onClick={onLoadMore}
                disabled={entriesLoading}
                className="rounded-md px-4 py-2 text-xs font-semibold text-zinc-300 transition-colors hover:bg-zinc-800 hover:text-zinc-100 disabled:opacity-50"
              >
                {entriesLoading ? t.saving : t.loadMore}
              </button>
            </div>
          )}
        </>
      )}
    </section>
  );
}

function AlertsSection({
  alertLog,
  showAlerts,
  t,
  onToggleSection,
}: {
  alertLog: AlertLogEntry[];
  showAlerts: boolean;
  t: Labels;
  onToggleSection: () => void;
}) {
  return (
    <section className="rounded-2xl bg-zinc-900 p-5 ring-1 ring-zinc-800">
      <header className="mb-4 flex items-center justify-between">
        <SectionLabel count={alertLog.length}>{t.alerts}</SectionLabel>
        <ToggleButton open={showAlerts} onClick={onToggleSection} />
      </header>

      {showAlerts &&
        (alertLog.length === 0 ? (
          <p className="py-3 text-sm text-zinc-500">{t.noAlerts}</p>
        ) : (
          <div className="-mx-5 overflow-x-auto px-5">
            <table className="w-full min-w-[400px] text-sm">
              <thead>
                <tr className="border-b border-zinc-800">
                  <th className="pb-2 pr-3 text-left text-[10px] font-bold uppercase tracking-wider text-zinc-500">
                    {t.time}
                  </th>
                  <th className="pb-2 pr-3 text-left text-[10px] font-bold uppercase tracking-wider text-zinc-500">
                    {t.headgate}
                  </th>
                  <th className="pb-2 pr-3 text-left text-[10px] font-bold uppercase tracking-wider text-zinc-500">
                    {t.via}
                  </th>
                  <th className="pb-2 pr-3 text-right text-[10px] font-bold uppercase tracking-wider text-zinc-500">
                    {t.reading}
                  </th>
                </tr>
              </thead>
              <tbody>
                {alertLog.map((a) => (
                  <tr key={a.id} className="border-b border-zinc-800/50 last:border-0">
                    <td className="py-2.5 pr-3 text-xs tabular-nums text-zinc-400">
                      {a.formatted_time}
                    </td>
                    <td className="py-2.5 pr-3 text-xs font-medium text-zinc-100">
                      {a.headgate_name}
                    </td>
                    <td className="py-2.5 pr-3">
                      <span
                        className={`inline-block rounded px-1.5 py-0.5 text-[10px] font-bold uppercase tracking-wider ring-1 ring-inset ${
                          a.alert_type === "high"
                            ? "bg-red-900/30 text-red-300 ring-red-900/50"
                            : "bg-blue-900/30 text-blue-300 ring-blue-900/50"
                        }`}
                      >
                        {a.alert_type === "high" ? t.alertHigh : t.alertLow}
                      </span>
                    </td>
                    <td className="py-2.5 pr-3 text-right text-xs font-semibold tabular-nums text-zinc-100">
                      {a.reading_value}
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        ))}
    </section>
  );
}

/* ── Main ─────────────────────────────────────────────────────────── */

export default function WaterAdminClient({
  initialSummary,
  initialHeadgates,
  initialUsers,
  initialAlertLog,
}: Props) {
  const router = useRouter();
  const [state, dispatch] = useReducer(
    reducer,
    reducerInit(initialSummary, initialHeadgates, initialUsers, initialAlertLog),
  );

  // One-time post-mount: detect language from cookie/navigator and start
  // the entries load + display polling.
  useEffect(() => {
    const detected = detectInitialLang();
    if (detected !== state.lang) {
      dispatch({ type: "SET_LANG", lang: detected });
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  // Persist language to cookie whenever it changes.
  useEffect(() => {
    if (typeof document === "undefined") return;
    document.cookie = `wl_lang=${state.lang}; path=/; max-age=31536000; SameSite=Lax`;
  }, [state.lang]);

  // Lazy-load the entries page on mount. We always fetch the first 50
  // immediately so the table can render rows; "Load more" appends more.
  useEffect(() => {
    let cancelled = false;
    (async () => {
      const data = await getWaterEntries(TUXEDO_BRAND_ID, PAGE_SIZE);
      if (cancelled) return;
      dispatch({ type: "SET_ENTRIES", entries: data, append: false });
      dispatch({ type: "SET_ENTRIES_PAGE", page: 0 });
      dispatch({
        type: "SET_ENTRIES_HAS_MORE",
        value: data.length === PAGE_SIZE,
      });
    })();
    return () => {
      cancelled = true;
    };
  }, []);

  // 30s polling on the display summary — keeps the cards fresh without
  // blocking the page. Previous data stays visible throughout. Uses a
  // ref to read the live countdown without tearing down the interval.
  const countdownRef = useRef(state.refreshCountdown);
  useEffect(() => {
    countdownRef.current = state.refreshCountdown;
  }, [state.refreshCountdown]);
  useEffect(() => {
    let cancelled = false;
    const refresh = async () => {
      const data = await getWaterDisplaySummary(TUXEDO_BRAND_ID);
      if (cancelled) return;
      dispatch({ type: "SET_DISPLAY_SUMMARY", summary: data });
      dispatch({ type: "RESET_COUNTDOWN", value: REFRESH_SECONDS });
    };
    const tick = setInterval(() => {
      const next = countdownRef.current - 1;
      if (next <= 0) {
        void refresh();
      } else {
        dispatch({ type: "DECREMENT_COUNTDOWN" });
      }
    }, 1000);
    return () => {
      cancelled = true;
      clearInterval(tick);
    };
  }, []);

  const t = LABELS[state.lang];

  /* ── Handlers ───────────────────────────────────────────────── */

  async function handleLogout() {
    await logoutWaterAdmin();
    window.location.href = "/water";
  }

  function handleChangeLang(next: "en" | "es") {
    dispatch({ type: "SET_LANG", lang: next });
  }

  async function handleAddHeadgate(e: React.FormEvent) {
    e.preventDefault();
    dispatch({ type: "SET_SAVING_HG", value: true });
    dispatch({ type: "SET_NEW_HG_ERROR", value: null });
    const result = await createWaterHeadgate(TUXEDO_BRAND_ID, state.newHgName, state.newHgUnit);
    if (result.success && result.headgate) {
      dispatch({
        type: "SET_HEADGATES",
        headgates: [result.headgate, ...state.headgates],
      });
      dispatch({ type: "SET_NEW_HG_NAME", value: "" });
      dispatch({ type: "SET_NEW_HG_UNIT", value: "CFS" });
      dispatch({ type: "SET_SAVING_HG", value: false });
      dispatch({ type: "TOGGLE", key: "showAddHg" });
    } else {
      dispatch({ type: "SET_NEW_HG_ERROR", value: result.error ?? t.saving });
      dispatch({ type: "SET_SAVING_HG", value: false });
    }
  }

  async function handleAddUser(e: React.FormEvent) {
    e.preventDefault();
    dispatch({ type: "SET_SAVING_USER", value: true });
    dispatch({ type: "SET_NEW_USER_ERROR", value: null });
    const result = await createWaterIrrigator(
      TUXEDO_BRAND_ID,
      state.newUserName,
      state.newUserLang,
    );
    if (result.success && result.user) {
      dispatch({
        type: "SET_USERS",
        users: [result.user, ...state.users],
      });
      dispatch({
        type: "SET_NEW_PIN",
        value: { name: result.user.name, pin: result.pin ?? "" },
      });
      dispatch({ type: "SET_NEW_USER_NAME", value: "" });
      dispatch({ type: "SET_NEW_USER_LANG", value: "es" });
      dispatch({ type: "SET_SAVING_USER", value: false });
      dispatch({ type: "TOGGLE", key: "showAddUser" });
    } else {
      dispatch({ type: "SET_NEW_USER_ERROR", value: result.error ?? t.saving });
      dispatch({ type: "SET_SAVING_USER", value: false });
    }
  }

  function handleEditHeadgate(id: string) {
    router.push(`/admin/water-log/headgates/${id}?from=/water/admin`);
  }

  function handleEditUser(id: string) {
    router.push(`/admin/water-log/users/${id}?from=/water/admin`);
  }

  /* ── Filter pipeline (client-side over loaded entries) ──────── */

  const filteredEntries = state.entries.filter((e) => {
    if (state.filterHeadgate && e.headgate_id !== state.filterHeadgate) return false;
    if (state.filterVia && e.submitted_via !== state.filterVia) return false;
    if (state.filterDateFrom) {
      const d = new Date(e.logged_at);
      if (d < new Date(state.filterDateFrom)) return false;
    }
    if (state.filterDateTo) {
      const d = new Date(e.logged_at);
      const to = new Date(state.filterDateTo);
      to.setHours(23, 59, 59, 999);
      if (d > to) return false;
    }
    return true;
  });

  const headgateOptions = state.headgates.map((hg) => ({ id: hg.id, name: hg.name }));

  return (
    <main className="min-h-screen bg-zinc-950 text-zinc-100">
      <AdminHeader
        title={t.title}
        subtitle={t.loggedInAs}
        lang={state.lang}
        onChangeLang={handleChangeLang}
        onLogout={handleLogout}
        t={t}
      />
      <div className="mx-auto max-w-2xl space-y-6 px-4 py-6">
        <DisplaySummarySection
          displaySummary={state.displaySummary}
          refreshCountdown={state.refreshCountdown}
          t={t}
        />

        <HeadgatesSection
          headgates={state.headgates}
          showHeadgates={state.showHeadgates}
          showAddHg={state.showAddHg}
          newHgName={state.newHgName}
          newHgUnit={state.newHgUnit}
          savingHg={state.savingHg}
          newHgError={state.newHgError}
          t={t}
          onToggleSection={() => dispatch({ type: "TOGGLE", key: "showHeadgates" })}
          onToggleAdd={() => dispatch({ type: "TOGGLE", key: "showAddHg" })}
          onChangeName={(v) => dispatch({ type: "SET_NEW_HG_NAME", value: v })}
          onChangeUnit={(v) => dispatch({ type: "SET_NEW_HG_UNIT", value: v })}
          onSubmit={handleAddHeadgate}
          onCancel={() => dispatch({ type: "TOGGLE", key: "showAddHg" })}
          onEdit={handleEditHeadgate}
        />

        <UsersSection
          users={state.users}
          showUsers={state.showUsers}
          showAddUser={state.showAddUser}
          newUserName={state.newUserName}
          newUserLang={state.newUserLang}
          savingUser={state.savingUser}
          newUserError={state.newUserError}
          newPin={state.newPin}
          t={t}
          onToggleSection={() => dispatch({ type: "TOGGLE", key: "showUsers" })}
          onToggleAdd={() => dispatch({ type: "TOGGLE", key: "showAddUser" })}
          onChangeName={(v) => dispatch({ type: "SET_NEW_USER_NAME", value: v })}
          onChangeLang={(v) => dispatch({ type: "SET_NEW_USER_LANG", value: v })}
          onSubmit={handleAddUser}
          onCancel={() => dispatch({ type: "TOGGLE", key: "showAddUser" })}
          onDismissPin={() => dispatch({ type: "SET_NEW_PIN", value: null })}
          onEdit={handleEditUser}
        />

        <EntriesSection
          entries={filteredEntries}
          entriesLoading={state.entriesLoading}
          entriesHasMore={state.entriesHasMore}
          showEntries={state.showEntries}
          filterDateFrom={state.filterDateFrom}
          filterDateTo={state.filterDateTo}
          filterHeadgate={state.filterHeadgate}
          filterVia={state.filterVia}
          headgateOptions={headgateOptions}
          t={t}
          onToggleSection={() => dispatch({ type: "TOGGLE", key: "showEntries" })}
          onChangeFilter={(field, value) => dispatch({ type: "SET_FILTER", field, value })}
          onClearFilters={() => dispatch({ type: "CLEAR_FILTERS" })}
          onLoadMore={async () => {
            const currentPage = state.entriesPage;
            const nextPage = currentPage + 1;
            const limit = (nextPage + 1) * PAGE_SIZE;
            dispatch({ type: "SET_ENTRIES_LOADING", value: true });
            const data = await getWaterEntries(TUXEDO_BRAND_ID, limit);
            dispatch({
              type: "SET_ENTRIES",
              entries: data,
              append: true,
            });
            dispatch({ type: "SET_ENTRIES_PAGE", page: nextPage });
            dispatch({
              type: "SET_ENTRIES_HAS_MORE",
              value: data.length === limit,
            });
            dispatch({ type: "SET_ENTRIES_LOADING", value: false });
          }}
        />

        <AlertsSection
          alertLog={state.alertLog}
          showAlerts={state.showAlerts}
          t={t}
          onToggleSection={() => dispatch({ type: "TOGGLE", key: "showAlerts" })}
        />

        <footer className="pt-4 text-center text-[11px] uppercase tracking-wider text-zinc-600">
          Tuxedo · Water Log
        </footer>
      </div>
    </main>
  );
}
