/**
 * HTTP layer for /admin/auth/* — reads/writes the refresh cookie, shapes the
 * JSON. All business rules live in auth.service.ts.
 *
 * Refresh cookie: httpOnly + Secure + SameSite=None (the admin portal is a
 * different origin — PLANNING.md §8/§10), scoped to /admin/auth so it is only
 * sent to /refresh and /logout.
 */
import type { CookieOptions, Request, Response } from 'express';
import { AppError } from '../../lib/AppError';
import { durationToMs } from '../../lib/duration';
import { parseBody } from '../../lib/parseRequest';
import { env } from '../../env';
import { loginSchema, forgotPasswordSchema, resetPasswordSchema } from './auth.schema';
import * as authService from './auth.service';

const REFRESH_COOKIE = 'gcs_admin_refresh';

const refreshCookieOptions = (): CookieOptions => ({
  httpOnly: true,
  secure: true,
  sameSite: 'none',
  path: '/admin/auth',
  maxAge: durationToMs(env.REFRESH_TOKEN_TTL),
});

function ctxOf(req: Request) {
  return {
    ip: req.ip ?? 'unknown',
    userAgent: req.get('user-agent') ?? undefined,
  };
}

function readRefreshCookie(req: Request): string | undefined {
  const jar = req.cookies as Record<string, string | undefined> | undefined;
  return jar?.[REFRESH_COOKIE];
}

function setSession(res: Response, session: authService.SessionResult): void {
  res.cookie(REFRESH_COOKIE, session.refreshToken, refreshCookieOptions());
  res.json({ accessToken: session.accessToken, admin: session.admin });
}

export async function login(req: Request, res: Response): Promise<void> {
  const { phone, password } = parseBody(loginSchema, req.body);
  setSession(res, await authService.login(phone, password, ctxOf(req)));
}

export async function refresh(req: Request, res: Response): Promise<void> {
  const raw = readRefreshCookie(req);
  if (!raw) throw AppError.unauthorized('No session');
  setSession(res, await authService.refresh(raw, ctxOf(req)));
}

export async function logout(req: Request, res: Response): Promise<void> {
  await authService.logout(readRefreshCookie(req));
  res.clearCookie(REFRESH_COOKIE, { path: '/admin/auth' });
  res.json({ ok: true });
}

export async function forgotPassword(req: Request, res: Response): Promise<void> {
  const { email } = parseBody(forgotPasswordSchema, req.body);
  await authService.forgotPassword(email);
  res.json({ ok: true }); // always 200 — no enumeration oracle (§8)
}

export async function resetPassword(req: Request, res: Response): Promise<void> {
  const { token, password } = parseBody(resetPasswordSchema, req.body);
  await authService.resetPassword(token, password);
  res.json({ ok: true });
}

export async function me(req: Request, res: Response): Promise<void> {
  res.json({ admin: await authService.me(req.admin!.id) });
}
