/**
 * Water Log — admin-facing server actions.
 *
 * Two access paths:
 *   1. Site-admin UI (`/admin/water-log`) — needs `can_manage_water_log`
 *      and runs brand-scoped via `withBrand()`.
 *   2. PIN-protected field-admin UI (`/water/admin`) — uses a separate
 *      `water_admin_sessions` cookie; `requireWaterAdminSession()` is the
 *      gate for those.
 *
 * All actions return either `{ success: true, ... }` or
 * `{ success: false, error }`. We never throw across the action boundary
 * for expected errors (duplicate name, invalid input) — those are user
 * feedback. Unexpected errors (DB outage, programmer error) propagate
 * and surface in the toast as a generic message.
 */
"use server";

import { cookies } from "next/headers";
import { and, desc, eq, gte, lte, sql, SQL } from "drizzle-orm";
import { getAdminUser } from "@/lib/admin-permissions";
import { withBrand } from "@/db/client";
import {
  waterHeadgates,
  waterIrrigators,
  waterLogEntries,
  waterAdminSessions,
  type WaterHeadgate,
  type WaterIrrigator,
  type WaterLogEntry,
} from "@/db/schema/water-log";
import { hashPin, generatePin, verifyPin } from "@/lib/water-log-pin";
import { logAuditEvent, logAlert } from "@/lib/water-log-audit";

// ── Types used by both server and client ────────────────────────────────────

export type AdminHeadgate = {
  id: string;
  name: string;
  status: "open" | "closed" | "maintenance";
  unit: string;
  active: boolean;
  headgate_token: string;
  last_used_at: string | null;
  high_threshold: number | null;
  low_threshold: number | null;
  max_flow_gpm: number | null;
  notes: string | null;
  created_at: string;
};

export type AdminIrrigator = {
  id: string;
  name: string;
  role: "irrigator" | "water_admin";
  active: boolean;
  language_preference: string;
  phone: string | null;
  notes: string | null;
  last_used_at: string | null;
  created_at: string;
};

export type AdminEntry = {
  id: string;
  headgate_id: string;
  user_id: string;
  headgate_name: string;
  user_name: string;
  measurement: number;
  unit: string;
  total_gallons: number | null;
  method: "manual" | "meter" | "estimate" | "qr";
  notes: string | null;
  submitted_via: string;
  photo_url: string | null;
  logged_at: string;
  logged_date: string | null;
};

export type WaterDisplayHeadgate = {
  id: string;
  name: string;
  unit: string;
  latest_entry: { measurement: number; user_name: string; logged_at: string } | null;
  last_logged_at: string | null;
  minutes_ago: number | null;
};

export type WaterDisplaySummary = {
  headgates: WaterDisplayHeadgate[];
  today_count: number;
  today_total: number;
  recent_entries: AdminEntry[];
};

export type AlertLogEntry = {
  id: string;
  alert_type: "high" | "low";
  threshold_value: number;
  reading_value: number;
  message_sent: string | null;
  sent_at: string;
  created_at: string;
  headgate_name: string;
  formatted_time: string;
};

// ── Auth helpers ───────────────────────────────────────────────────────────

async function requireWaterAdminPermission() {
  const adminUser = await getAdminUser();
  if (!adminUser) return { ok: false as const, error: "Not authenticated" };
  if (
    !adminUser.can_manage_water_log &&
    adminUser.role !== "platform_admin"
  ) {
    return { ok: false as const, error: "Not authorized" };
  }
  return { ok: true as const, adminUser };
}

/**
 * For the `/water/admin` (PIN) portal. Returns the admin + brand if a
 * valid session cookie is present. Falls back to a 401-shaped error.
 */
export async function requireWaterAdminSession(): Promise<
  | { ok: true; adminUserId: string; brandId: string }
  | { ok: false; error: string }
> {
  const cookieStore = await cookies();
  const sessionId = cookieStore.get("wl_admin_session")?.value;
  if (!sessionId) return { ok: false, error: "Not signed in" };

  return withBrand(globalThis.__TUXEDO_BRAND_ID__ ?? "", async () => {
    // session lookup must use platform-admin to read across brands
    const { withPlatformAdmin } = await import("@/db/client");
    return withPlatformAdmin(async (db) => {
      const rows = await db
        .select()
        .from(waterAdminSessions)
        .where(eq(waterAdminSessions.id, sessionId))
        .limit(1);
      const row = rows[0];
      if (!row) return { ok: false as const, error: "Session not found" };
      if (row.expiresAt.getTime() < Date.now()) {
        return { ok: false as const, error: "Session expired" };
      }
      return {
        ok: true as const,
        adminUserId: row.adminUserId,
        brandId: row.brandId,
      };
    });
  });
}

// Global hint used by the field admin portal: water log is currently
// scoped to the Tuxedo brand only. Surfacing this in one place makes it
// easy to lift later when we add multi-tenant water log.
declare global {
  // eslint-disable-next-line no-var
  var __TUXEDO_BRAND_ID__: string | undefined;
}
globalThis.__TUXEDO_BRAND_ID__ ??= "64294306-5f42-463d-a5e8-2ad6c81a96de";

// ── Mappers (DB row → client shape) ────────────────────────────────────────

function mapHeadgate(h: WaterHeadgate): AdminHeadgate {
  return {
    id: h.id,
    name: h.name,
    status: (h.status as AdminHeadgate["status"]) ?? "open",
    unit: h.unit ?? "CFS",
    active: h.active,
    headgate_token: h.headgateToken,
    last_used_at: h.lastUsedAt?.toISOString() ?? null,
    high_threshold: h.highThreshold != null ? Number(h.highThreshold) : null,
    low_threshold: h.lowThreshold != null ? Number(h.lowThreshold) : null,
    max_flow_gpm: h.maxFlowGpm != null ? Number(h.maxFlowGpm) : null,
    notes: h.notes,
    created_at: h.createdAt.toISOString(),
  };
}

function mapIrrigator(i: WaterIrrigator): AdminIrrigator {
  return {
    id: i.id,
    name: i.name,
    role: (i.role as AdminIrrigator["role"]) ?? "irrigator",
    active: i.active,
    language_preference: i.languagePreference,
    phone: i.phone,
    notes: i.notes,
    last_used_at: i.lastUsedAt?.toISOString() ?? null,
    created_at: i.createdAt.toISOString(),
  };
}

function mapEntry(
  e: WaterLogEntry & { headgate_name: string; user_name: string },
): AdminEntry {
  return {
    id: e.id,
    headgate_id: e.headgateId,
    user_id: e.irrigatorId,
    headgate_name: e.headgate_name,
    user_name: e.user_name,
    measurement: Number(e.measurement),
    unit: e.unit,
    total_gallons: e.totalGallons != null ? Number(e.totalGallons) : null,
    method: (e.method as AdminEntry["method"]) ?? "manual",
    notes: e.notes,
    submitted_via: e.submittedVia,
    photo_url: e.photoUrl,
    logged_at: e.loggedAt.toISOString(),
    logged_date: e.loggedDate,
  };
}

// ── Headgate CRUD ──────────────────────────────────────────────────────────

export async function createWaterHeadgate(
  brandId: string,
  name: string,
  unit: string = "CFS",
  options: { highThreshold?: number | null; lowThreshold?: number | null; notes?: string | null } = {},
): Promise<{ success: boolean; headgate?: AdminHeadgate; error?: string }> {
  const auth = await requireWaterAdminPermission();
  if (!auth.ok) return { success: false, error: auth.error };
  const trimmed = name?.trim();
  if (!trimmed) return { success: false, error: "Name is required" };
  if (trimmed.length > 80) return { success: false, error: "Name is too long" };

  return withBrand(brandId, async (db) => {
    const existing = await db
      .select({ id: waterHeadgates.id })
      .from(waterHeadgates)
      .where(
        and(eq(waterHeadgates.brandId, brandId), eq(waterHeadgates.name, trimmed)),
      )
      .limit(1);
    if (existing[0]) {
      return { success: false, error: "A headgate with that name already exists" };
    }
    const [row] = await db
      .insert(waterHeadgates)
      .values({
        brandId,
        name: trimmed,
        unit,
        highThreshold: options.highThreshold?.toString() ?? null,
        lowThreshold: options.lowThreshold?.toString() ?? null,
        notes: options.notes ?? null,
        headgateToken: `hg_${cryptoRandomHex(12)}`,
      })
      .returning();
    if (!row) return { success: false, error: "Insert failed" };
    await logAuditEvent({
      brandId,
      actorId: auth.adminUser.user_id ?? null,
      actorLabel: auth.adminUser.email ?? auth.adminUser.display_name ?? "admin",
      action: "create",
      entityType: "headgate",
      entityId: row.id,
      details: { name: row.name, unit: row.unit },
    });
    return { success: true, headgate: mapHeadgate(row) };
  });
}

export async function updateWaterHeadgate(
  headgateId: string,
  name: string,
  active: boolean,
  unit?: string,
  highThreshold?: number | null,
  lowThreshold?: number | null,
  notes?: string | null,
  status?: AdminHeadgate["status"],
): Promise<{ success: boolean; error?: string }> {
  const auth = await requireWaterAdminPermission();
  if (!auth.ok) return { success: false, error: auth.error };

  // Headgates aren't directly brand-scoped in the URL — look up brand first.
  const brand = await withPlatformAdminBrandOf(headgateId);
  if (!brand) return { success: false, error: "Headgate not found" };

  return withBrand(brand, async (db) => {
    const trimmed = name?.trim();
    if (!trimmed) return { success: false, error: "Name is required" };
    const existing = await db
      .select({ id: waterHeadgates.id })
      .from(waterHeadgates)
      .where(
        and(
          eq(waterHeadgates.brandId, brand),
          eq(waterHeadgates.name, trimmed),
        ),
      )
      .limit(1);
    if (existing[0] && existing[0].id !== headgateId) {
      return { success: false, error: "Another headgate already uses that name" };
    }
    const updated = await db
      .update(waterHeadgates)
      .set({
        name: trimmed,
        active,
        unit: unit ?? "CFS",
        highThreshold: highThreshold?.toString() ?? null,
        lowThreshold: lowThreshold?.toString() ?? null,
        notes: notes ?? null,
        status: status ?? "open",
      })
      .where(eq(waterHeadgates.id, headgateId))
      .returning();
    if (!updated[0]) return { success: false, error: "Headgate not found" };
    await logAuditEvent({
      brandId: brand,
      actorId: auth.adminUser.user_id ?? null,
      actorLabel: auth.adminUser.email ?? auth.adminUser.display_name ?? "admin",
      action: "update",
      entityType: "headgate",
      entityId: headgateId,
      details: { name: trimmed, active, status, unit, highThreshold, lowThreshold },
    });
    return { success: true };
  });
}

export async function deleteWaterHeadgate(
  headgateId: string,
): Promise<{ success: boolean; error?: string }> {
  const auth = await requireWaterAdminPermission();
  if (!auth.ok) return { success: false, error: auth.error };
  const brand = await withPlatformAdminBrandOf(headgateId);
  if (!brand) return { success: false, error: "Headgate not found" };
  return withBrand(brand, async (db) => {
    const deleted = await db
      .delete(waterHeadgates)
      .where(eq(waterHeadgates.id, headgateId))
      .returning({ id: waterHeadgates.id });
    if (!deleted[0]) return { success: false, error: "Headgate not found" };
    await logAuditEvent({
      brandId: brand,
      actorId: auth.adminUser.user_id ?? null,
      actorLabel: auth.adminUser.email ?? auth.adminUser.display_name ?? "admin",
      action: "delete",
      entityType: "headgate",
      entityId: headgateId,
    });
    return { success: true };
  });
}

export async function regenerateHeadgateToken(
  headgateId: string,
): Promise<{ success: boolean; token?: string; error?: string }> {
  const auth = await requireWaterAdminPermission();
  if (!auth.ok) return { success: false, error: auth.error };
  const brand = await withPlatformAdminBrandOf(headgateId);
  if (!brand) return { success: false, error: "Headgate not found" };
  return withBrand(brand, async (db) => {
    const token = `hg_${cryptoRandomHex(12)}`;
    const updated = await db
      .update(waterHeadgates)
      .set({ headgateToken: token })
      .where(eq(waterHeadgates.id, headgateId))
      .returning({ token: waterHeadgates.headgateToken });
    if (!updated[0]) return { success: false, error: "Headgate not found" };
    await logAuditEvent({
      brandId: brand,
      actorId: auth.adminUser.user_id ?? null,
      actorLabel: auth.adminUser.email ?? auth.adminUser.display_name ?? "admin",
      action: "regenerate_token",
      entityType: "headgate",
      entityId: headgateId,
    });
    return { success: true, token: updated[0].token };
  });
}

export async function getWaterHeadgatesAdmin(
  brandId: string,
): Promise<AdminHeadgate[]> {
  const auth = await requireWaterAdminPermission();
  if (!auth.ok) return [];
  return withBrand(brandId, async (db) => {
    const rows = await db
      .select()
      .from(waterHeadgates)
      .where(eq(waterHeadgates.brandId, brandId))
      .orderBy(desc(waterHeadgates.createdAt));
    return rows.map(mapHeadgate);
  });
}

// ── Irrigator (user) CRUD ──────────────────────────────────────────────────

export async function getWaterIrrigators(brandId: string): Promise<AdminIrrigator[]> {
  const auth = await requireWaterAdminPermission();
  if (!auth.ok) return [];
  return withBrand(brandId, async (db) => {
    const rows = await db
      .select()
      .from(waterIrrigators)
      .where(eq(waterIrrigators.brandId, brandId))
      .orderBy(desc(waterIrrigators.createdAt));
    return rows.map(mapIrrigator);
  });
}

export type CreateUserResult = {
  success: boolean;
  user?: AdminIrrigator;
  pin?: string;
  error?: string;
};

export async function createWaterUser(
  brandId: string,
  name: string,
  role: "irrigator" | "water_admin" = "irrigator",
  language: string = "en",
  phone?: string | null,
): Promise<CreateUserResult> {
  const auth = await requireWaterAdminPermission();
  if (!auth.ok) return { success: false, error: auth.error };
  const trimmed = name?.trim();
  if (!trimmed) return { success: false, error: "Name is required" };
  if (trimmed.length > 80) return { success: false, error: "Name is too long" };
  if (!["en", "es"].includes(language)) {
    return { success: false, error: "Invalid language" };
  }

  const pin = generatePin();
  const pinHash = hashPin(pin);

  const result = await withBrand(brandId, async (db) => {
    const existing = await db
      .select({ id: waterIrrigators.id })
      .from(waterIrrigators)
      .where(
        and(
          eq(waterIrrigators.brandId, brandId),
          eq(waterIrrigators.name, trimmed),
        ),
      )
      .limit(1);
    if (existing[0]) {
      return { success: false as const, error: "A user with that name already exists" };
    }
    const [row] = await db
      .insert(waterIrrigators)
      .values({
        brandId,
        name: trimmed,
        pinHash,
        role,
        languagePreference: language,
        phone: phone ?? null,
      })
      .returning();
    if (!row) return { success: false as const, error: "Insert failed" };
    return { success: true as const, user: row };
  });
  if (!result.success) return { success: false, error: result.error };

  await logAuditEvent({
    brandId,
    actorId: auth.adminUser.user_id ?? null,
    actorLabel: auth.adminUser.email ?? auth.adminUser.display_name ?? "admin",
    action: "create",
    entityType: "user",
    entityId: result.user.id,
    details: { name: result.user.name, role },
  });
  return { success: true, user: mapIrrigator(result.user), pin };
}

export async function createWaterIrrigator(
  brandId: string,
  name: string,
  language: string = "en",
): Promise<CreateUserResult> {
  return createWaterUser(brandId, name, "irrigator", language);
}

export async function updateWaterIrrigator(
  irrigatorId: string,
  name: string,
  active: boolean,
  language: string,
  role: "irrigator" | "water_admin",
  phone?: string | null,
  notes?: string | null,
): Promise<{ success: boolean; error?: string }> {
  const auth = await requireWaterAdminPermission();
  if (!auth.ok) return { success: false, error: auth.error };
  const brand = await withPlatformAdminBrandOfIrrigator(irrigatorId);
  if (!brand) return { success: false, error: "User not found" };
  return withBrand(brand, async (db) => {
    const trimmed = name?.trim();
    if (!trimmed) return { success: false, error: "Name is required" };
    if (!["en", "es"].includes(language)) {
      return { success: false, error: "Invalid language" };
    }
    const updated = await db
      .update(waterIrrigators)
      .set({
        name: trimmed,
        active,
        languagePreference: language,
        role,
        phone: phone ?? null,
        notes: notes ?? null,
      })
      .where(eq(waterIrrigators.id, irrigatorId))
      .returning();
    if (!updated[0]) return { success: false, error: "User not found" };
    await logAuditEvent({
      brandId: brand,
      actorId: auth.adminUser.user_id ?? null,
      actorLabel: auth.adminUser.email ?? auth.adminUser.display_name ?? "admin",
      action: "update",
      entityType: "user",
      entityId: irrigatorId,
      details: { name: trimmed, active, role, language },
    });
    return { success: true };
  });
}

export async function deleteWaterUser(
  userId: string,
): Promise<{ success: boolean; error?: string }> {
  const auth = await requireWaterAdminPermission();
  if (!auth.ok) return { success: false, error: auth.error };
  const brand = await withPlatformAdminBrandOfIrrigator(userId);
  if (!brand) return { success: false, error: "User not found" };
  return withBrand(brand, async (db) => {
    const deleted = await db
      .delete(waterIrrigators)
      .where(eq(waterIrrigators.id, userId))
      .returning({ id: waterIrrigators.id });
    if (!deleted[0]) return { success: false, error: "User not found" };
    await logAuditEvent({
      brandId: brand,
      actorId: auth.adminUser.user_id ?? null,
      actorLabel: auth.adminUser.email ?? auth.adminUser.display_name ?? "admin",
      action: "delete",
      entityType: "user",
      entityId: userId,
    });
    return { success: true };
  });
}

export async function resetWaterIrrigatorPin(
  userId: string,
): Promise<{ success: boolean; pin?: string; error?: string }> {
  const auth = await requireWaterAdminPermission();
  if (!auth.ok) return { success: false, error: auth.error };
  const brand = await withPlatformAdminBrandOfIrrigator(userId);
  if (!brand) return { success: false, error: "User not found" };
  const pin = generatePin();
  const pinHash = hashPin(pin);
  return withBrand(brand, async (db) => {
    const updated = await db
      .update(waterIrrigators)
      .set({ pinHash })
      .where(eq(waterIrrigators.id, userId))
      .returning({ id: waterIrrigators.id });
    if (!updated[0]) return { success: false, error: "User not found" };
    // Invalidate existing sessions for safety
    await db.execute(
      sql`DELETE FROM water_sessions WHERE irrigator_id = ${userId}`,
    );
    await logAuditEvent({
      brandId: brand,
      actorId: auth.adminUser.user_id ?? null,
      actorLabel: auth.adminUser.email ?? auth.adminUser.display_name ?? "admin",
      action: "reset_pin",
      entityType: "user",
      entityId: userId,
    });
    return { success: true, pin };
  });
}

// ── Entry CRUD ─────────────────────────────────────────────────────────────

export async function getWaterEntries(
  brandId: string,
  limit: number = 50,
): Promise<AdminEntry[]> {
  const auth = await requireWaterAdminPermission();
  if (!auth.ok) return [];
  const safeLimit = Math.min(Math.max(limit, 1), 1000);
  return withBrand(brandId, async (db) => {
    const rows = await db.execute<{
      id: string;
      headgate_id: string;
      irrigator_id: string;
      headgate_name: string;
      user_name: string;
      measurement: string;
      unit: string;
      total_gallons: string | null;
      method: string;
      notes: string | null;
      submitted_via: string;
      photo_url: string | null;
      logged_at: string;
      logged_date: string | null;
    }>(sql`
      SELECT
        e.id, e.headgate_id, e.irrigator_id,
        h.name AS headgate_name,
        i.name AS user_name,
        e.measurement::text, e.unit,
        e.total_gallons::text, e.method, e.notes, e.submitted_via,
        e.photo_url, e.logged_at, e.logged_date
      FROM water_log_entries e
      JOIN water_headgates h ON h.id = e.headgate_id
      JOIN water_irrigators i ON i.id = e.irrigator_id
      WHERE e.brand_id = ${brandId}
      ORDER BY e.logged_at DESC
      LIMIT ${safeLimit}
    `);
    return rows.rows.map((r) => ({
      id: r.id,
      headgate_id: r.headgate_id,
      user_id: r.irrigator_id,
      headgate_name: r.headgate_name,
      user_name: r.user_name,
      measurement: Number(r.measurement),
      unit: r.unit,
      total_gallons: r.total_gallons != null ? Number(r.total_gallons) : null,
      method: (r.method ?? "manual") as AdminEntry["method"],
      notes: r.notes,
      submitted_via: r.submitted_via,
      photo_url: r.photo_url,
      logged_at: r.logged_at,
      logged_date: r.logged_date,
    }));
  });
}

export async function getWaterEntryById(entryId: string): Promise<AdminEntry | null> {
  const auth = await requireWaterAdminPermission();
  if (!auth.ok) return null;
  const brand = await withPlatformAdminBrandOfEntry(entryId);
  if (!brand) return null;
  return withBrand(brand, async (db) => {
    const rows = await db.execute<{
      id: string;
      headgate_id: string;
      irrigator_id: string;
      headgate_name: string;
      user_name: string;
      measurement: string;
      unit: string;
      total_gallons: string | null;
      method: string;
      notes: string | null;
      submitted_via: string;
      photo_url: string | null;
      logged_at: string;
      logged_date: string | null;
    }>(sql`
      SELECT
        e.id, e.headgate_id, e.irrigator_id,
        h.name AS headgate_name,
        i.name AS user_name,
        e.measurement::text, e.unit,
        e.total_gallons::text, e.method, e.notes, e.submitted_via,
        e.photo_url, e.logged_at, e.logged_date
      FROM water_log_entries e
      JOIN water_headgates h ON h.id = e.headgate_id
      JOIN water_irrigators i ON i.id = e.irrigator_id
      WHERE e.id = ${entryId}
      LIMIT 1
    `);
    const r = rows.rows[0];
    if (!r) return null;
    return {
      id: r.id,
      headgate_id: r.headgate_id,
      user_id: r.irrigator_id,
      headgate_name: r.headgate_name,
      user_name: r.user_name,
      measurement: Number(r.measurement),
      unit: r.unit,
      total_gallons: r.total_gallons != null ? Number(r.total_gallons) : null,
      method: (r.method ?? "manual") as AdminEntry["method"],
      notes: r.notes,
      submitted_via: r.submitted_via,
      photo_url: r.photo_url,
      logged_at: r.logged_at,
      logged_date: r.logged_date,
    };
  });
}

export async function updateWaterEntry(
  entryId: string,
  measurement: number,
  notes: string | null,
  unit?: string,
  method?: AdminEntry["method"],
): Promise<{ success: boolean; error?: string }> {
  const auth = await requireWaterAdminPermission();
  if (!auth.ok) return { success: false, error: auth.error };
  if (!Number.isFinite(measurement) || measurement < 0) {
    return { success: false, error: "Measurement must be a non-negative number" };
  }
  const brand = await withPlatformAdminBrandOfEntry(entryId);
  if (!brand) return { success: false, error: "Entry not found" };
  return withBrand(brand, async (db) => {
    const updated = await db
      .update(waterLogEntries)
      .set({
        measurement: measurement.toString(),
        unit: unit ?? "CFS",
        method: method ?? "manual",
        notes,
      })
      .where(eq(waterLogEntries.id, entryId))
      .returning({ id: waterLogEntries.id });
    if (!updated[0]) return { success: false, error: "Entry not found" };
    await logAuditEvent({
      brandId: brand,
      actorId: auth.adminUser.user_id ?? null,
      actorLabel: auth.adminUser.email ?? auth.adminUser.display_name ?? "admin",
      action: "update",
      entityType: "entry",
      entityId: entryId,
      details: { measurement, unit, method },
    });
    return { success: true };
  });
}

export async function deleteWaterEntry(
  entryId: string,
): Promise<{ success: boolean; error?: string }> {
  const auth = await requireWaterAdminPermission();
  if (!auth.ok) return { success: false, error: auth.error };
  const brand = await withPlatformAdminBrandOfEntry(entryId);
  if (!brand) return { success: false, error: "Entry not found" };
  return withBrand(brand, async (db) => {
    const deleted = await db
      .delete(waterLogEntries)
      .where(eq(waterLogEntries.id, entryId))
      .returning({ id: waterLogEntries.id });
    if (!deleted[0]) return { success: false, error: "Entry not found" };
    await logAuditEvent({
      brandId: brand,
      actorId: auth.adminUser.user_id ?? null,
      actorLabel: auth.adminUser.email ?? auth.adminUser.display_name ?? "admin",
      action: "delete",
      entityType: "entry",
      entityId: entryId,
    });
    return { success: true };
  });
}

// ── Display summary (used by the field-admin dashboard) ────────────────────

export async function getWaterDisplaySummary(
  brandId: string,
): Promise<WaterDisplaySummary | null> {
  const auth = await requireWaterAdminPermission();
  if (!auth.ok) return null;
  return withBrand(brandId, async (db) => {
    // Headgates with their latest entry
    const headgateRows = await db.execute<{
      id: string;
      name: string;
      unit: string;
      last_logged_at: string | null;
      latest_user: string | null;
      latest_measurement: string | null;
    }>(sql`
      SELECT
        h.id, h.name, h.unit,
        (
          SELECT MAX(e.logged_at)
          FROM water_log_entries e
          WHERE e.headgate_id = h.id
        ) AS last_logged_at,
        (
          SELECT i.name
          FROM water_log_entries e2
          JOIN water_irrigators i ON i.id = e2.irrigator_id
          WHERE e2.headgate_id = h.id
          ORDER BY e2.logged_at DESC
          LIMIT 1
        ) AS latest_user,
        (
          SELECT e3.measurement::text
          FROM water_log_entries e3
          WHERE e3.headgate_id = h.id
          ORDER BY e3.logged_at DESC
          LIMIT 1
        ) AS latest_measurement
      FROM water_headgates h
      WHERE h.brand_id = ${brandId}
      ORDER BY h.name ASC
    `);

    const now = Date.now();
    const headgates: WaterDisplayHeadgate[] = headgateRows.rows.map((r) => {
      const last = r.last_logged_at ? new Date(r.last_logged_at) : null;
      const minutesAgo = last ? Math.floor((now - last.getTime()) / 60000) : null;
      return {
        id: r.id,
        name: r.name,
        unit: r.unit ?? "CFS",
        latest_entry:
          r.latest_measurement != null && r.latest_user && r.last_logged_at
            ? {
                measurement: Number(r.latest_measurement),
                user_name: r.latest_user,
                logged_at: r.last_logged_at,
              }
            : null,
        last_logged_at: r.last_logged_at,
        minutes_ago: minutesAgo,
      };
    });

    // Today's entries
    const todayCount = await db.execute<{ count: string; total: string | null }>(sql`
      SELECT
        COUNT(*)::text AS count,
        COALESCE(SUM(measurement), 0)::text AS total
      FROM water_log_entries
      WHERE brand_id = ${brandId}
        AND logged_date = (NOW() AT TIME ZONE 'UTC')::date
    `);
    const today = todayCount.rows[0] ?? { count: "0", total: "0" };

    // Recent entries (last 10)
    const recent = await db.execute<{
      id: string;
      headgate_id: string;
      irrigator_id: string;
      headgate_name: string;
      user_name: string;
      measurement: string;
      unit: string;
      total_gallons: string | null;
      method: string;
      notes: string | null;
      submitted_via: string;
      photo_url: string | null;
      logged_at: string;
      logged_date: string | null;
    }>(sql`
      SELECT
        e.id, e.headgate_id, e.irrigator_id,
        h.name AS headgate_name,
        i.name AS user_name,
        e.measurement::text, e.unit,
        e.total_gallons::text, e.method, e.notes, e.submitted_via,
        e.photo_url, e.logged_at, e.logged_date
      FROM water_log_entries e
      JOIN water_headgates h ON h.id = e.headgate_id
      JOIN water_irrigators i ON i.id = e.irrigator_id
      WHERE e.brand_id = ${brandId}
      ORDER BY e.logged_at DESC
      LIMIT 10
    `);

    return {
      headgates,
      today_count: parseInt(today.count, 10) || 0,
      today_total: parseFloat(today.total ?? "0") || 0,
      recent_entries: recent.rows.map((r) => ({
        id: r.id,
        headgate_id: r.headgate_id,
        user_id: r.irrigator_id,
        headgate_name: r.headgate_name,
        user_name: r.user_name,
        measurement: Number(r.measurement),
        unit: r.unit,
        total_gallons: r.total_gallons != null ? Number(r.total_gallons) : null,
        method: (r.method ?? "manual") as AdminEntry["method"],
        notes: r.notes,
        submitted_via: r.submitted_via,
        photo_url: r.photo_url,
        logged_at: r.logged_at,
        logged_date: r.logged_date,
      })),
    };
  });
}

export async function getWaterAlertLog(
  brandId: string,
  limit: number = 50,
): Promise<AlertLogEntry[]> {
  const auth = await requireWaterAdminPermission();
  if (!auth.ok) return [];
  return withBrand(brandId, async (db) => {
    const rows = await db.execute<{
      id: string;
      alert_type: string;
      threshold_value: string | null;
      reading_value: string | null;
      message_sent: string | null;
      sent_at: string | null;
      created_at: string;
      headgate_name: string | null;
    }>(sql`
      SELECT
        a.id, a.alert_type,
        NULL::text AS threshold_value,
        NULL::text AS reading_value,
        a.message AS message_sent,
        a.sent_at,
        a.created_at,
        h.name AS headgate_name
      FROM water_alert_log a
      LEFT JOIN water_headgates h ON h.id = a.headgate_id
      WHERE a.brand_id = ${brandId}
      ORDER BY a.created_at DESC
      LIMIT ${Math.min(Math.max(limit, 1), 500)}
    `);
    return rows.rows.map((r) => ({
      id: r.id,
      alert_type: r.alert_type === "low" ? "low" : "high",
      threshold_value: 0,
      reading_value: 0,
      message_sent: r.message_sent,
      sent_at: r.sent_at ?? r.created_at,
      created_at: r.created_at,
      headgate_name: r.headgate_name ?? "Unknown",
      formatted_time: new Date(r.created_at).toLocaleString("en-US", {
        month: "short",
        day: "numeric",
        hour: "numeric",
        minute: "2-digit",
      }),
    }));
  });
}

// ── Helpers ────────────────────────────────────────────────────────────────

/**
 * Find the brand_id of a headgate by id. Uses `withPlatformAdmin` because
 * we don't know which brand to scope the lookup to yet.
 */
async function withPlatformAdminBrandOf(headgateId: string): Promise<string | null> {
  const { withPlatformAdmin } = await import("@/db/client");
  return withPlatformAdmin(async (db) => {
    const rows = await db
      .select({ brandId: waterHeadgates.brandId })
      .from(waterHeadgates)
      .where(eq(waterHeadgates.id, headgateId))
      .limit(1);
    return rows[0]?.brandId ?? null;
  });
}

async function withPlatformAdminBrandOfIrrigator(userId: string): Promise<string | null> {
  const { withPlatformAdmin } = await import("@/db/client");
  return withPlatformAdmin(async (db) => {
    const rows = await db
      .select({ brandId: waterIrrigators.brandId })
      .from(waterIrrigators)
      .where(eq(waterIrrigators.id, userId))
      .limit(1);
    return rows[0]?.brandId ?? null;
  });
}

async function withPlatformAdminBrandOfEntry(entryId: string): Promise<string | null> {
  const { withPlatformAdmin } = await import("@/db/client");
  return withPlatformAdmin(async (db) => {
    const rows = await db
      .select({ brandId: waterLogEntries.brandId })
      .from(waterLogEntries)
      .where(eq(waterLogEntries.id, entryId))
      .limit(1);
    return rows[0]?.brandId ?? null;
  });
}

function cryptoRandomHex(bytes: number): string {
  const arr = new Uint8Array(bytes);
  // Use globalThis.crypto when available (Node 19+, all browsers).
  // Fall back to require("crypto") for older runtimes.
  if (typeof globalThis.crypto?.getRandomValues === "function") {
    globalThis.crypto.getRandomValues(arr);
  } else {
    // eslint-disable-next-line @typescript-eslint/no-require-imports
    const nodeCrypto = require("node:crypto") as typeof import("node:crypto");
    nodeCrypto.randomFillSync(arr);
  }
  return Array.from(arr, (b) => b.toString(16).padStart(2, "0")).join("");
}

// Re-export for the field action to do an admin-PIN check.
export { verifyPin };
export { logAlert };
