import type { ConsentCategory, ConsentGrantMeta } from "./consent-types";
import type { IConsent } from "./consent.interface";

/** Cookie name written by the anonymous consent banner. */
export const CONSENT_COOKIE_NAME = "cc_consent";

/**
 * Parses a raw Cookie header string and returns the consent categories the
 * anonymous visitor granted via the banner cookie. Returns null when the
 * consent cookie is absent or empty.
 *
 * Expected cookie value format: comma-separated category names,
 * e.g. "necessary,analytics,marketing".
 */
export function extractAnonymousConsent(
  cookieHeader: string,
): ConsentCategory[] | null {
  const cookies = parseCookieHeader(cookieHeader);
  const raw = cookies.get(CONSENT_COOKIE_NAME);
  if (!raw) return null;
  const categories = raw
    .split(",")
    .map((c) => c.trim())
    .filter(Boolean) as ConsentCategory[];
  return categories.length > 0 ? categories : null;
}

/**
 * Migrates anonymous consent categories into an authenticated user's consent
 * record. Calls IConsent.grant for each category with method "signup-migration"
 * so the migration is traceable in the audit log. No-op when cookieState is
 * null (visitor had no consent cookie).
 */
export async function migrateAnonymousConsent(opts: {
  consent: IConsent;
  cookieState: ConsentCategory[] | null;
  bannerVersion?: string;
  policyVersion?: string;
}): Promise<void> {
  const { consent, cookieState, bannerVersion, policyVersion } = opts;
  if (!cookieState) return;
  const meta: ConsentGrantMeta = { method: "signup-migration" };
  if (bannerVersion !== undefined) meta.bannerVersion = bannerVersion;
  if (policyVersion !== undefined) meta.policyVersion = policyVersion;
  for (const category of cookieState) {
    await consent.grant(category, meta);
  }
}

function parseCookieHeader(cookieHeader: string): Map<string, string> {
  const map = new Map<string, string>();
  for (const part of cookieHeader.split(";")) {
    const eqIdx = part.indexOf("=");
    if (eqIdx === -1) continue;
    const name = part.slice(0, eqIdx).trim();
    const value = part.slice(eqIdx + 1).trim();
    if (name) map.set(name, value);
  }
  return map;
}
