// Browser session profile owner enforcement.
//
// Extracted as a pure function so the fail-closed contract can be unit
// tested without spinning up a Worker. The Worker still performs the
// surrounding decrypt flow inline (see src/worker.ts) — only the
// owner-vs-job assertion lives here.
//
// Fail-closed contract: a job must have a non-empty ownerId AND that
// ownerId must equal the profile's ownerId. A null/undefined/empty
// job.ownerId always fails (no implicit "skip the check").

import type { BrowserSessionRepo } from '../db/browser-session-repo.js';

export interface OwnerCheckProfile {
  id: number;
  ownerId: string;
}

export interface OwnerCheckJob {
  id: string;
  ownerId: string | null | undefined;
}

/**
 * Throw if the profile cannot be used by this job. Audits every failure.
 *
 * Returns void on success (caller may continue to decrypt). Throws
 * Error('Browser session profile owner mismatch') on any rejection.
 */
export function assertProfileOwner(
  profile: OwnerCheckProfile,
  job: OwnerCheckJob,
  sessRepo: Pick<BrowserSessionRepo, 'audit'>,
): void {
  if (!job.ownerId || profile.ownerId !== job.ownerId) {
    sessRepo.audit({
      actorUserId: job.ownerId ?? null,
      ownerId: profile.ownerId,
      profileId: profile.id,
      action: 'use',
      result: 'error',
      reason: `owner mismatch (job.owner=${job.ownerId ?? 'null'} vs profile.owner=${profile.ownerId})`,
      jobId: job.id,
    });
    throw new Error('Browser session profile owner mismatch');
  }
}
