/**
 * HttpOnly cookie helpers for the Cloudflare OAuth encrypted token blob.
 *
 * The blob is the same base64 payload produced by `encryptTokens()`; this module
 * just centralises the cookie name and attributes so every call site agrees.
 * Prod uses the `__Host-` prefix (requires Secure + Path=/ + no Domain). Dev
 * (HTTP) drops the prefix and `Secure` because browsers reject Secure cookies
 * on plain http.
 */

import { isDev } from './envs';
import { parseCookies } from './authUtils';

const PROD_COOKIE = '__Host-cf_oauth_token';
const DEV_COOKIE = 'cf_oauth_token';

/** Short-lived, flow-scoped PKCE verifier cookie set during connect initiation and cleared on callback. */
const PROD_VERIFIER_COOKIE_PREFIX = '__Host-cf_oauth_verifier_';
const DEV_VERIFIER_COOKIE_PREFIX = 'cf_oauth_verifier_';
export const VERIFIER_COOKIE_TTL_SECONDS = 10 * 60;

/**
 * Short-lived nonce cookie that binds an OAuth login `state` to the browser that
 * initiated the flow. Prevents login-CSRF / session fixation:
 * a callback replayed in a different browser will not carry the matching nonce.
 * Prod uses the `__Host-` prefix; dev drops it (and Secure) for plain http.
 */
const PROD_NONCE_COOKIE = '__Host-oauth_nonce';
const DEV_NONCE_COOKIE = 'oauth_nonce';
export const NONCE_COOKIE_TTL_SECONDS = 10 * 60;

function nonceCookieName(env: Env): string {
	return isDev(env) ? DEV_NONCE_COOKIE : PROD_NONCE_COOKIE;
}

/** Default to 30 days; callers can override based on the refresh-token lifetime. */
const DEFAULT_MAX_AGE_SECONDS = 30 * 24 * 60 * 60;

function tokenCookieName(env: Env): string {
	return isDev(env) ? DEV_COOKIE : PROD_COOKIE;
}

function baseAttributes(env: Env): string {
	// SameSite=Lax so the cookie rides top-level redirects back from the OAuth provider.
	return isDev(env)
		? 'Path=/; HttpOnly; SameSite=Lax'
		: 'Path=/; HttpOnly; Secure; SameSite=Lax';
}

/** Build a Set-Cookie header value that installs the encrypted blob. */
export function buildTokenCookie(env: Env, blob: string, maxAgeSeconds: number = DEFAULT_MAX_AGE_SECONDS): string {
	return `${tokenCookieName(env)}=${encodeURIComponent(blob)}; ${baseAttributes(env)}; Max-Age=${maxAgeSeconds}`;
}

/** Build a Set-Cookie header value that clears the token cookie. */
export function buildClearTokenCookie(env: Env): string {
	return `${tokenCookieName(env)}=; ${baseAttributes(env)}; Max-Age=0`;
}

/** Read a named cookie value from the request's Cookie header, if present. */
export function readRequestCookie(request: Request | undefined | null, name: string): string | null {
	const header = request?.headers.get('Cookie');
	if (!header) return null;
	const cookies = parseCookies(header);
	return cookies[name] ?? null;
}

/** Read the encrypted token blob from the request's Cookie header, if present. */
export function readTokenCookie(request: Request | undefined | null, env: Env): string | null {
	return readRequestCookie(request, tokenCookieName(env));
}

function verifierCookieName(env: Env, flowId: string): string {
	const prefix = isDev(env) ? DEV_VERIFIER_COOKIE_PREFIX : PROD_VERIFIER_COOKIE_PREFIX;
	return `${prefix}${flowId}`;
}

/** Build a Set-Cookie header value for the short-lived PKCE verifier. */
export function buildVerifierCookie(env: Env, flowId: string, value: string, maxAgeSeconds: number = VERIFIER_COOKIE_TTL_SECONDS): string {
	return `${verifierCookieName(env, flowId)}=${encodeURIComponent(value)}; ${baseAttributes(env)}; Max-Age=${maxAgeSeconds}`;
}

/** Build a Set-Cookie header value that clears the PKCE verifier cookie. */
export function buildClearVerifierCookie(env: Env, flowId: string): string {
	return `${verifierCookieName(env, flowId)}=; ${baseAttributes(env)}; Max-Age=0`;
}

/** Read the PKCE verifier cookie value, if present. */
export function readVerifierCookie(request: Request | undefined | null, env: Env, flowId: string): string | null {
	return readRequestCookie(request, verifierCookieName(env, flowId));
}

/** Build a Set-Cookie header value that installs the OAuth state nonce. */
export function buildOAuthNonceCookie(env: Env, nonce: string, maxAgeSeconds: number = NONCE_COOKIE_TTL_SECONDS): string {
	return `${nonceCookieName(env)}=${encodeURIComponent(nonce)}; ${baseAttributes(env)}; Max-Age=${maxAgeSeconds}`;
}

/** Build a Set-Cookie header value that clears the OAuth state nonce cookie. */
export function buildClearOAuthNonceCookie(env: Env): string {
	return `${nonceCookieName(env)}=; ${baseAttributes(env)}; Max-Age=0`;
}

/** Read the OAuth state nonce cookie value, if present. */
export function readOAuthNonceCookie(request: Request | undefined | null, env: Env): string | null {
	return readRequestCookie(request, nonceCookieName(env));
}
