/**
 * Water Log — admin settings (PIN-protected /water/admin portal).
 *
 * The `/water/admin` portal is gated by its own 4-digit PIN (separate
 * from the irrigators' PIN). That PIN is *hashed* and stored in
 * `water_admin_settings` (one row per brand).
 *
 * PIN verification lives in `src/lib/water-admin-pin-auth.ts` (no
 * server actions, no Neon Auth). This file only handles the
 * platform-admin-gated `/admin/water-log/settings` UI which sets /
 * updates the PIN and other admin settings.
 */
"use server";

import { eq } from "drizzle-orm";
import { withBrand } from "@/db/client";
import {
  waterAdminSettings,
  waterAdminSessions,
  type WaterAdminSettings,
} from "@/db/schema/water-log";
import { getAdminUser } from "@/lib/admin-permissions";
import { hashPin, generatePin } from "@/lib/water-log-pin";
import { logAuditEvent } from "@/lib/water-log-audit";

export type AdminSettings = {
  enabled: boolean;
  sessionDurationHours: number;
  canEditEntries: boolean;
  canDeleteEntries: boolean;
  canExportCsv: boolean;
  alertPhone: string | null;
  alertsEnabled: boolean;
  /** The currently configured PIN, in plain text. Only returned on
   *  read right after the admin regenerates it; otherwise null. */
  pin: string | null;
};

function mapSettings(s: WaterAdminSettings): AdminSettings {
  return {
    enabled: s.enabled,
    sessionDurationHours: s.sessionDurationHours,
    canEditEntries: s.canEditEntries,
    canDeleteEntries: s.canDeleteEntries,
    canExportCsv: s.canExportCsv,
    alertPhone: s.alertPhone,
    alertsEnabled: s.alertsEnabled,
    pin: null, // never returned unless just regenerated
  };
}

export async function getWaterAdminSettings(
  brandId: string,
): Promise<AdminSettings | null> {

const adminUser = await getAdminUser();
  if (!adminUser) return null;
  if (
    !adminUser.can_manage_water_log &&
    adminUser.role !== "platform_admin"
  ) {
    return null;
  }
  return withBrand(brandId, async (db) => {
    const rows = await db
      .select()
      .from(waterAdminSettings)
      .where(eq(waterAdminSettings.brandId, brandId))
      .limit(1);
    if (!rows[0]) {
      // Lazy-initialize default settings the first time the page is hit
      const [created] = await db
        .insert(waterAdminSettings)
        .values({ brandId })
        .returning();
      if (!created) return null;
      return { ...mapSettings(created), pin: null };
    }
    return mapSettings(rows[0]);
  });
}

export async function saveWaterAdminSettings(
  brandId: string,
  settings: Partial<AdminSettings>,
): Promise<{ success: boolean; settings?: AdminSettings; error?: string }> {

const adminUser = await getAdminUser();
  if (!adminUser) return { success: false, error: "Not authenticated" };
  if (
    !adminUser.can_manage_water_log &&
    adminUser.role !== "platform_admin"
  ) {
    return { success: false, error: "Not authorized" };
  }

  if (
    settings.sessionDurationHours != null &&
    (settings.sessionDurationHours < 1 || settings.sessionDurationHours > 168)
  ) {
    return { success: false, error: "Session duration must be 1–168 hours" };
  }

  return withBrand(brandId, async (db) => {
    const update: Partial<WaterAdminSettings> = {};
    if (settings.enabled != null) update.enabled = settings.enabled;
    if (settings.sessionDurationHours != null)
      update.sessionDurationHours = settings.sessionDurationHours;
    if (settings.canEditEntries != null)
      update.canEditEntries = settings.canEditEntries;
    if (settings.canDeleteEntries != null)
      update.canDeleteEntries = settings.canDeleteEntries;
    if (settings.canExportCsv != null)
      update.canExportCsv = settings.canExportCsv;
    if (settings.alertPhone !== undefined)
      update.alertPhone = settings.alertPhone;
    if (settings.alertsEnabled != null)
      update.alertsEnabled = settings.alertsEnabled;
    update.updatedBy = adminUser.user_id ?? adminUser.id ?? null;

    // Upsert: insert if missing, update if present.
    const updated = await db
      .insert(waterAdminSettings)
      .values({ brandId, ...update })
      .onConflictDoUpdate({
        target: waterAdminSettings.brandId,
        set: update,
      })
      .returning();

    await logAuditEvent({
      brandId,
      actorId: adminUser.user_id ?? null,
      actorLabel: adminUser.email ?? adminUser.display_name ?? "admin",
      action: "update",
      entityType: "settings",
      details: { ...update },
    });
    return { success: true, settings: mapSettings(updated[0]) };
  });
}

/**
 * Generate a fresh PIN, hash it, and save it on the brand. Returns the
 * plaintext PIN *once* — caller is responsible for showing it to the
 * admin and never persisting it.
 */
export async function regenerateAdminPin(
  brandId: string,
): Promise<{ success: boolean; pin?: string; error?: string }> {

const adminUser = await getAdminUser();
  if (!adminUser) return { success: false, error: "Not authenticated" };
  if (
    !adminUser.can_manage_water_log &&
    adminUser.role !== "platform_admin"
  ) {
    return { success: false, error: "Not authorized" };
  }
  const pin = generatePin();
  const pinHash = hashPin(pin);
  return withBrand(brandId, async (db) => {
    // The upsert and the session-invalidation delete are independent —
    // they touch different tables and don't reference each other's
    // results, so run them in parallel.
    await Promise.all([
      db
        .insert(waterAdminSettings)
        .values({ brandId, pinHash })
        .onConflictDoUpdate({
          target: waterAdminSettings.brandId,
          set: { pinHash, updatedBy: adminUser.user_id ?? adminUser.id ?? null },
        }),
      // Invalidate any existing admin sessions for safety
      db
        .delete(waterAdminSessions)
        .where(eq(waterAdminSessions.brandId, brandId)),
    ]);
    await logAuditEvent({
      brandId,
      actorId: adminUser.user_id ?? null,
      actorLabel: adminUser.email ?? adminUser.display_name ?? "admin",
      action: "regenerate_admin_pin",
      entityType: "settings",
    });
    return { success: true, pin };
  });
}
