import { getJSONCookie, setJSONCookie } from "./cookies";

/**
 * The visitor's response to the cookie banner, kept in the browser so the
 * banner is not shown again on every page.
 *
 * This cookie is itself strictly necessary - it only remembers the choice -
 * so it needs no consent of its own, and is written whether the visitor
 * accepts or rejects. Rejecting declines optional cookies only; the strictly
 * necessary ones (payment session data, language, the payment provider's
 * cookies at checkout) are used either way.
 */
export const COOKIE_CONSENT_COOKIE = "ye_cookie_consent";

/** A year: long enough not to nag a returning visitor, and re-asked if the notice changes. */
const CONSENT_DAYS = 365;

export type CookieConsentDecision = "accepted" | "rejected";

export interface StoredCookieConsent {
  /** Random id created when the visitor chose, sent to the server with the record. */
  id: string;
  /** Cookie Notice version the visitor responded to, e.g. "2026-09-04-v1". */
  version: string;
  decision: CookieConsentDecision;
  /** ISO timestamp. */
  at: string;
}

export function readCookieConsent(): StoredCookieConsent | null {
  const stored = getJSONCookie<StoredCookieConsent>(COOKIE_CONSENT_COOKIE);
  if (!stored || typeof stored.id !== "string" || !stored.decision) return null;
  return stored;
}

/**
 * Should the banner be shown?
 *
 * Yes if the visitor has not responded, or responded to a different version of
 * the Cookie Notice than the one published now - acknowledging the old text is
 * not acknowledging the new one. If the current version could not be fetched,
 * an existing response is left standing rather than re-asking on every page.
 */
export function needsCookieConsent(currentVersion: string | null): boolean {
  const stored = readCookieConsent();
  if (!stored) return true;
  if (currentVersion && stored.version !== currentVersion) return true;
  return false;
}

/**
 * May optional (non-essential) cookies or trackers be used for this visitor?
 *
 * Only after an explicit Accept. The site has none today; anything added later
 * - analytics, pixels, video embeds that track - must check this first and not
 * load when it returns false. Essential cookies never depend on it.
 */
export function hasAcceptedOptionalCookies(): boolean {
  return readCookieConsent()?.decision === "accepted";
}

export function saveCookieConsent(
  decision: CookieConsentDecision,
  version: string | null,
): StoredCookieConsent {
  const consent: StoredCookieConsent = {
    id: newVisitorId(),
    version: version ?? "",
    decision,
    at: new Date().toISOString(),
  };
  setJSONCookie(COOKIE_CONSENT_COOKIE, consent, CONSENT_DAYS);
  return consent;
}

/**
 * A random v4 uuid. Created only at the moment the visitor responds - never
 * before - and used solely to tie this browser to its own consent record.
 */
function newVisitorId(): string {
  if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
    return crypto.randomUUID();
  }

  // crypto.randomUUID needs a secure context; fall back to the same shape.
  const bytes = new Uint8Array(16);
  if (typeof crypto !== "undefined" && typeof crypto.getRandomValues === "function") {
    crypto.getRandomValues(bytes);
  } else {
    for (let i = 0; i < bytes.length; i++) bytes[i] = Math.floor(Math.random() * 256);
  }
  bytes[6] = (bytes[6] & 0x0f) | 0x40; // version 4
  bytes[8] = (bytes[8] & 0x3f) | 0x80; // RFC 4122 variant

  const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
  return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
}
