import { SecurityError } from "./errors.ts";

const TRUSTED_HTML = Symbol("wrnexus.trusted-html");

export interface TrustedHtmlPolicy {
  /** Stable policy name used in diagnostics and CSP/Trusted Types integration. */
  name: string;
  /** Application-supplied, reviewed sanitizer. It must return sanitized HTML. */
  sanitize(input: string): string;
}

export interface TrustedHtmlValue {
  readonly policy: string;
  readonly value: string;
  readonly [TRUSTED_HTML]: true;
}

export function createTrustedHtml(input: string, policy: TrustedHtmlPolicy): TrustedHtmlValue {
  if (!policy?.name?.trim() || typeof policy.sanitize !== "function") {
    throw new SecurityError(
      "WRN-SEC-TRUSTED-HTML-POLICY",
      "Trusted HTML requires a named sanitizer policy.",
    );
  }
  const value = policy.sanitize(String(input));
  if (typeof value !== "string") {
    throw new SecurityError(
      "WRN-SEC-TRUSTED-HTML-RESULT",
      `Trusted HTML policy '${policy.name}' must return a string.`,
    );
  }
  return Object.freeze({ policy: policy.name.trim(), value, [TRUSTED_HTML]: true as const });
}

export function isTrustedHtml(value: unknown): value is TrustedHtmlValue {
  return Boolean(
    value &&
    typeof value === "object" &&
    (value as Partial<TrustedHtmlValue>)[TRUSTED_HTML] === true &&
    typeof (value as Partial<TrustedHtmlValue>).value === "string",
  );
}

export function unwrapTrustedHtml(value: TrustedHtmlValue): string {
  if (!isTrustedHtml(value)) {
    throw new SecurityError(
      "WRN-SEC-TRUSTED-HTML-REQUIRED",
      "Raw HTML must be produced by createTrustedHtml().",
    );
  }
  return value.value;
}
