import { open, seal, type EncryptionKeyring } from "@wrnexus/encryption";
import type { AuthSecretProtector } from "./types.ts";

const PURPOSE_PREFIX = "wrn-auth-secret:v1:";

type AuthSecretPurpose = "totp" | "oauth-access" | "oauth-refresh";

function bindPurpose(value: string, purpose: AuthSecretPurpose): string {
  return `${PURPOSE_PREFIX}${purpose}\0${value}`;
}

function revealBoundValue(value: string, purpose: AuthSecretPurpose): string {
  if (!value.startsWith(PURPOSE_PREFIX)) {
    // Backward compatibility for ciphertext written before purpose binding was introduced.
    return value;
  }
  const separator = value.indexOf("\0", PURPOSE_PREFIX.length);
  if (separator < 0) throw new Error("WRN-AUTH-SECRET-PAYLOAD");
  const storedPurpose = value.slice(PURPOSE_PREFIX.length, separator);
  if (storedPurpose !== purpose) throw new Error("WRN-AUTH-SECRET-PURPOSE");
  return value.slice(separator + 1);
}

/**
 * Protect TOTP and OAuth secrets with the versioned @wrnexus/encryption keyring.
 * Rotated keys continue to decrypt old records while new writes use the active key.
 * New payloads are bound to their purpose so encrypted values cannot be swapped
 * between TOTP, OAuth access-token, and OAuth refresh-token fields.
 */
export function createAuthSecretProtector(keyring: EncryptionKeyring): AuthSecretProtector {
  return {
    async protect(value, purpose) {
      return seal(bindPurpose(value, purpose), keyring);
    },
    async reveal(value, purpose) {
      return revealBoundValue(await open(value, keyring), purpose);
    },
  };
}
