// Local type aliases matching the contracts in @repo/core-shared/instrumentation.
// Kept inline to avoid a build-graph cycle between core-testing and core-shared.
type Breadcrumb = {
  category: string;
  message: string;
  level?: "info" | "warning" | "error";
  data?: Record<string, unknown>;
};

type CaptureContext = {
  tags?: Record<string, string>;
  extras?: Record<string, unknown>;
  fingerprint?: string[];
};

interface ILogger {
  captureException(err: unknown, ctx?: CaptureContext): void;
  captureMessage(msg: string, level?: "info" | "warning" | "error", ctx?: CaptureContext): void;
  addBreadcrumb(b: Breadcrumb): void;
  setUser(user: { id: string } | null): void;
}

export type RecordedCapture =
  | { kind: "exception"; err: unknown; ctx?: CaptureContext }
  | { kind: "message"; message: string; level?: "info" | "warning" | "error"; ctx?: CaptureContext };

// Inlined to avoid a tooling → core import (boundary rule). Mirrors the
// implementation in @repo/core-shared/instrumentation/reported-flag.ts.
const REPORTED = "__sentryReported" as const;

function isReported(err: unknown): boolean {
  return (
    err !== null &&
    typeof err === "object" &&
    Boolean((err as Record<string, unknown>)[REPORTED])
  );
}

function markReported(err: unknown): void {
  if (err !== null && typeof err === "object" && !isReported(err)) {
    Object.defineProperty(err, REPORTED, {
      value: true,
      enumerable: false,
      configurable: false,
      writable: false,
    });
  }
}

export class RecordingLogger implements ILogger {
  captures: RecordedCapture[] = [];
  breadcrumbs: Breadcrumb[] = [];
  users: Array<{ id: string } | null> = [];

  captureException(err: unknown, ctx?: CaptureContext): void {
    if (isReported(err)) return;
    this.captures.push({ kind: "exception", err, ctx });
    markReported(err);
  }

  captureMessage(
    message: string,
    level?: "info" | "warning" | "error",
    ctx?: CaptureContext,
  ): void {
    this.captures.push({ kind: "message", message, level, ctx });
  }

  addBreadcrumb(b: Breadcrumb): void {
    this.breadcrumbs.push(b);
  }

  setUser(user: { id: string } | null): void {
    this.users.push(user);
  }

  reset(): void {
    this.captures = [];
    this.breadcrumbs = [];
    this.users = [];
  }

  findCapture(
    predicate: (c: RecordedCapture) => boolean,
  ): RecordedCapture | undefined {
    return this.captures.find(predicate);
  }
}
