/**
 * 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). Sessions are tracked in
 * `water_admin_sessions`.
 *
 * There is currently no per-admin-user PIN — a single brand-wide admin
 * PIN. If you need per-user PINs (e.g. for an audit trail of which
 * admin entered the portal), swap `pin_hash` for `admin_user_pins` and
 * key sessions by `admin_user_id`.
 */
"use server";

import { cookies } from "next/headers";
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, verifyPin, validatePin, 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) => {
    await 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
    await 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 };
  });
}

/**
 * PIN verify for the `/water/admin` portal. Creates a session row and
 * sets the `wl_admin_session` cookie.
 */
export async function verifyWaterAdminPin(
  brandId: string,
  pin: string,
): Promise<{ success: boolean; session_id?: string; error?: string }> {
  const formatError = validatePin(pin);
  if (formatError) return { success: false, error: formatError };

  return withBrand(brandId, async (db) => {
    const rows = await db
      .select()
      .from(waterAdminSettings)
      .where(eq(waterAdminSettings.brandId, brandId))
      .limit(1);
    const settings = rows[0];
    if (!settings) {
      return { success: false, error: "Admin portal not configured" };
    }
    if (!settings.enabled) {
      return { success: false, error: "Admin portal is disabled" };
    }
    if (!settings.pinHash) {
      return { success: false, error: "No PIN configured — generate one in /admin/water-log/settings" };
    }
    if (!verifyPin(pin, settings.pinHash)) {
      await new Promise((r) => setTimeout(r, 200));
      return { success: false, error: "Invalid PIN" };
    }

    // Tie the session to the calling site admin (best-effort).
    const adminUser = await getAdminUser();

    const expiresAt = new Date(
      Date.now() + settings.sessionDurationHours * 60 * 60 * 1000,
    );
    const [session] = await db
      .insert(waterAdminSessions)
      .values({
        brandId,
        adminUserId: adminUser?.user_id ?? adminUser?.id ?? "00000000-0000-0000-0000-000000000000",
        pinHashUsed: settings.pinHash,
        expiresAt,
      })
      .returning({ id: waterAdminSessions.id });
    if (!session) return { success: false, error: "Failed to create session" };

    const cookieStore = await cookies();
    cookieStore.set("wl_admin_session", session.id, {
      httpOnly: true,
      secure: process.env.NODE_ENV === "production",
      sameSite: "lax",
      maxAge: settings.sessionDurationHours * 3600,
      path: "/",
    });

    return { success: true, session_id: session.id };
  });
}
