/**
 * Water Log — server-side cookie I/O.
 *
 * Companion to `./session.ts` (which holds the cookie names + types).
 * **Server-only** — every helper calls `cookies()` from
 * `next/headers`, which is not available in client components.
 *
 * The "cookie set must happen outside the pg transaction" invariant
 * (documented in commit `ca79896` and `src/lib/water-admin-pin-auth.ts`)
 * is preserved by the shape of `setSessionCookie` and
 * `clearSessionCookie` below — they are pure cookie I/O and never
 * touch a database.
 */

import "server-only";
import { cookies } from "next/headers";
import {
  WL_ADMIN_SESSION_COOKIE,
  WL_SESSION_COOKIE,
  type SessionCookieName,
} from "./session";

export { WL_SESSION_COOKIE, WL_ADMIN_SESSION_COOKIE } from "./session";
export type {
  SessionCookieName,
  FieldSession,
  FieldSessionError,
  FieldSessionResult,
  AdminSession,
} from "./session";

export type SessionCookieOptions = {
  /** Lifetime in hours. Translated to `maxAge` in seconds for `cookies.set`. */
  hours: number;
  /** Optional override for `secure`. Defaults to NODE_ENV === "production". */
  secure?: boolean;
};

const DEFAULT_COOKIE_PATH = "/";

/**
 * Set a session cookie. **Must be called outside any pg transaction.**
 *
 * Calling `cookies().set()` from inside a pg transaction corrupts
 * Next.js's request-scoped AsyncLocalStorage — that's the bug that
 * commit `ca79896` fixed in the admin portal and that the field portal
 * is being brought into line with.
 */
export async function setSessionCookie(
  name: SessionCookieName,
  value: string,
  opts: SessionCookieOptions,
): Promise<void> {
  const cookieStore = await cookies();
  cookieStore.set(name, value, {
    httpOnly: true,
    secure: opts.secure ?? process.env.NODE_ENV === "production",
    sameSite: "lax",
    maxAge: opts.hours * 3600,
    path: DEFAULT_COOKIE_PATH,
  });
}

/** Clear a session cookie. Idempotent. Safe to call inside or outside a tx. */
export async function clearSessionCookie(name: SessionCookieName): Promise<void> {
  const cookieStore = await cookies();
  cookieStore.delete(name);
}

/**
 * Read the value of a session cookie (or null). Read-only.
 *
 * Note: `httpOnly` cookies set via `setSessionCookie` are NOT visible
 * to `document.cookie` in the browser. This is intentional — it means
 * XSS can't steal the session token. Client components that need to
 * know "is the user signed in?" must round-trip a server action,
 * not sniff `document.cookie`.
 */
export async function readSessionCookie(
  name: SessionCookieName,
): Promise<string | null> {
  const cookieStore = await cookies();
  return cookieStore.get(name)?.value ?? null;
}

/**
 * Convenience wrapper for the "is the user signed in?" check on the
 * field portal — reads `wl_session`. Returns the session id (the
 * `water_sessions.id` row UUID) or null.
 */
export async function readFieldSessionId(): Promise<string | null> {
  return readSessionCookie(WL_SESSION_COOKIE);
}

/**
 * Convenience wrapper for the admin portal — reads `wl_admin_session`.
 */
export async function readAdminSessionId(): Promise<string | null> {
  return readSessionCookie(WL_ADMIN_SESSION_COOKIE);
}