import * as Sentry from "@sentry/nextjs";
import type { CaptureContext, SeverityLevel } from "@sentry/nextjs";

export type RemoteLogLevel = "warn" | "error" | "fatal";

export interface SentryLogPayload {
  level: RemoteLogLevel;
  component: string;
  message: string;
  data: unknown[];
  formatValue: (value: unknown) => string;
}

export function reportSentryLog(payload: SentryLogPayload): void {
  try {
    const error = findError(payload.data);
    const captureContext = toSentryCaptureContext(payload);

    if (error) {
      Sentry.captureException(error, captureContext);
      return;
    }

    Sentry.captureMessage(
      payload.message ||
        `[${payload.component}] ${payload.level.toUpperCase()} log`,
      captureContext,
    );
  } catch {
    // Logging must never break the app runtime.
  }
}

function toSentryCaptureContext({
  level,
  component,
  message,
  data,
  formatValue,
}: SentryLogPayload): CaptureContext {
  return {
    level: toSentrySeverityLevel(level),
    tags: {
      component,
      log_level: level,
    },
    extra: {
      component,
      message,
      data: data.map((item) => formatValue(item)),
    },
  };
}

function toSentrySeverityLevel(level: RemoteLogLevel): SeverityLevel {
  return level === "warn" ? "warning" : level;
}

function findError(args: unknown[]): Error | null {
  return args.find((arg): arg is Error => arg instanceof Error) ?? null;
}
