/**
 * Request-time session helpers for host and admin pages, server actions and route handlers.
 * Server-only (reads cookies and the database). Every page AND every action/route calls
 * requireHost()/requireAdmin() itself — layouts are never trusted as the only gate.
 */
import { cache } from 'react';
import { cookies } from 'next/headers';
import { redirect } from 'next/navigation';
import { getDb } from '@pintrush/db';
import type { VenueRole, VenueStatus } from '@pintrush/db';
import { formSecret } from '../server-env';
import { LOGIN_PATH, SESSION_COOKIE, sessionCookieOptions } from './cookies';
import { signSession, verifySession, type AdminSession, type HostSession, type SessionKind } from './session-token';

export interface HostContext {
  user: { id: string; name: string; email: string; role: VenueRole };
  venue: {
    id: string;
    name: string;
    slug: string;
    joinCode: string;
    timezone: string;
    status: VenueStatus;
    address: string | null;
    version: number;
  };
}

export interface AdminContext {
  admin: { id: string; name: string; email: string };
}

/**
 * The signed-in host, re-read from the database on every request (deduplicated per render with
 * React cache) so a removed user, a role change or a cancelled venue takes effect immediately.
 */
export const getHostContext = cache(async (): Promise<HostContext | null> => {
  const token = (await cookies()).get(SESSION_COOKIE.host)?.value;
  const claims = await verifySession('host', token, formSecret());
  if (!claims) return null;
  const user = await getDb().venueUser.findFirst({
    where: { id: claims.sub, venueId: claims.venueId },
    select: {
      id: true,
      name: true,
      email: true,
      role: true,
      venue: {
        select: { id: true, name: true, slug: true, joinCode: true, timezone: true, status: true, address: true, version: true },
      },
    },
  });
  if (!user || user.venue.status === 'CANCELLED') return null;
  const { venue, ...rest } = user;
  return { user: rest, venue };
});

export const getAdminContext = cache(async (): Promise<AdminContext | null> => {
  const token = (await cookies()).get(SESSION_COOKIE.admin)?.value;
  const claims = await verifySession('admin', token, formSecret());
  if (!claims) return null;
  const admin = await getDb().platformAdmin.findUnique({
    where: { id: claims.sub },
    select: { id: true, name: true, email: true },
  });
  return admin ? { admin } : null;
});

function loginRedirect(kind: SessionKind, next?: string): never {
  redirect(next ? `${LOGIN_PATH[kind]}?next=${encodeURIComponent(next)}` : LOGIN_PATH[kind]);
}

/** Signed-in host or a redirect to /host/login. `next` = where to return after signing in. */
export async function requireHost(next?: string): Promise<HostContext> {
  const ctx = await getHostContext();
  if (!ctx) loginRedirect('host', next);
  return ctx;
}

/** Signed-in platform admin or a redirect to /admin/login. */
export async function requireAdmin(next?: string): Promise<AdminContext> {
  const ctx = await getAdminContext();
  if (!ctx) loginRedirect('admin', next);
  return ctx;
}

/** Venue settings, TV links and staff are owner-only; hosts run events. */
export function isOwner(ctx: HostContext): boolean {
  return ctx.user.role === 'OWNER';
}

export async function startHostSession(claims: HostSession): Promise<void> {
  const token = await signSession('host', claims, formSecret());
  (await cookies()).set(SESSION_COOKIE.host, token, sessionCookieOptions());
}

export async function startAdminSession(claims: AdminSession): Promise<void> {
  const token = await signSession('admin', claims, formSecret());
  (await cookies()).set(SESSION_COOKIE.admin, token, sessionCookieOptions());
}

export async function endSession(kind: SessionKind): Promise<void> {
  (await cookies()).delete(SESSION_COOKIE[kind]);
}
