import * as Sentry from "@sentry/nextjs";
import type {
  ErrorReportingLevel,
  ErrorReportingService,
  ErrorReportingUser,
} from "./error-reporting-service";
import type { NotificationService } from "../notifications/notification-service";

type SentryLike = typeof Sentry;

export type GlitchtipErrorReportingServiceOptions = {
  enabled: boolean;
};

// GlitchTip speaks the Sentry protocol; @sentry/nextjs can send to GlitchTip via DSN.
export class GlitchtipErrorReportingService implements ErrorReportingService {
  constructor(
    private readonly options: GlitchtipErrorReportingServiceOptions,
    private readonly notifications?: NotificationService,
    private readonly sentry: SentryLike = Sentry,
  ) {}

  async captureException(error: unknown, context?: Record<string, unknown>) {
    if (!this.options.enabled) return undefined;
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const result = this.sentry.captureException(error, context as any) as any;

    // Send to Gotify if it's considered critical or if we just want all exceptions there
    // For now, let's send all exceptions to Gotify as requested "notify me via gotify about critical error messages"
    // We'll treat all captureException calls as potentially critical or at least noteworthy
    if (this.notifications) {
      const errorMessage =
        error instanceof Error ? error.message : String(error);
      const contextStr = context
        ? `\nContext: ${JSON.stringify(context, null, 2)}`
        : "";

      await this.notifications.notify({
        title: "🔥 Critical Error Captured",
        message: `Error: ${errorMessage}${contextStr}`,
        priority: 7,
      });
    }

    return result;
  }

  captureMessage(message: string, level: ErrorReportingLevel = "error") {
    if (!this.options.enabled) return undefined;
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    return this.sentry.captureMessage(message, level as any) as any;
  }

  setUser(user: ErrorReportingUser | null) {
    if (!this.options.enabled) return;
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    this.sentry.setUser(user as any);
  }

  setTag(key: string, value: string) {
    if (!this.options.enabled) return;
    this.sentry.setTag(key, value);
  }

  withScope<T>(fn: () => T, context?: Record<string, unknown>) {
    if (!this.options.enabled) return fn();

    return this.sentry.withScope((scope) => {
      if (context) {
        for (const [key, value] of Object.entries(context)) {
          scope.setExtra(key, value);
        }
      }
      return fn();
    });
  }
}
