/**
 * Sentry Error Tracking Integration
 * Agent 4: Production Deployment
 *
 * Provides error tracking and reporting with Sentry.
 * Note: Requires @sentry/nextjs package when implementing full integration.
 */

import { env } from '../config';
import { logger } from '../logging';

interface SentryContext {
  user?: {
    id?: string;
    email?: string;
    username?: string;
  };
  tags?: Record<string, string>;
  extra?: Record<string, unknown>;
}

interface BreadcrumbData {
  category: string;
  message: string;
  level?: 'debug' | 'info' | 'warning' | 'error';
  data?: Record<string, unknown>;
}

/**
 * Sentry error handler (stub implementation)
 * Replace with actual @sentry/nextjs integration when package is installed
 */
class SentryHandler {
  private isEnabled: boolean;
  private dsn: string | undefined;
  private breadcrumbs: BreadcrumbData[] = [];
  private maxBreadcrumbs = 100;

  constructor() {
    this.dsn = env.sentryDsn;
    this.isEnabled = !!this.dsn && env.isProduction;

    if (this.isEnabled) {
      logger.info('Sentry error tracking enabled', {
        environment: env.nodeEnv,
      });
    } else if (env.isProduction && !this.dsn) {
      logger.warn('Sentry DSN not configured - error tracking disabled');
    }
  }

  /**
   * Capture an exception and send to Sentry
   */
  captureException(error: Error, context?: SentryContext): string {
    const eventId = this.generateEventId();

    // Log the error
    logger.error('Error captured', error, {
      eventId,
      ...context?.tags,
      ...context?.extra,
    });

    if (this.isEnabled) {
      // In a real implementation, this would send to Sentry
      // For now, we log the error details
      this.logToSentry('exception', {
        eventId,
        error: {
          name: error.name,
          message: error.message,
          stack: error.stack,
        },
        context,
        breadcrumbs: this.breadcrumbs.slice(-20),
      });
    }

    return eventId;
  }

  /**
   * Capture a message and send to Sentry
   */
  captureMessage(
    message: string,
    level: 'debug' | 'info' | 'warning' | 'error' = 'info',
    context?: SentryContext
  ): string {
    const eventId = this.generateEventId();

    // Log the message
    const logFn = level === 'error' ? logger.error : level === 'warning' ? logger.warn : logger.info;
    logFn.call(logger, message, { eventId, ...context?.tags });

    if (this.isEnabled) {
      this.logToSentry('message', {
        eventId,
        message,
        level,
        context,
      });
    }

    return eventId;
  }

  /**
   * Set user context for error tracking
   */
  setUser(user: SentryContext['user'] | null): void {
    if (this.isEnabled && user) {
      logger.debug('Sentry user context set', { userId: user.id });
    }
  }

  /**
   * Set extra context for error tracking
   */
  setContext(name: string, context: Record<string, unknown>): void {
    if (this.isEnabled) {
      logger.debug('Sentry context set', { name, ...context });
    }
  }

  /**
   * Add a breadcrumb for debugging
   */
  addBreadcrumb(breadcrumb: BreadcrumbData): void {
    this.breadcrumbs.push({
      ...breadcrumb,
      level: breadcrumb.level || 'info',
    });

    // Keep only the last N breadcrumbs
    if (this.breadcrumbs.length > this.maxBreadcrumbs) {
      this.breadcrumbs = this.breadcrumbs.slice(-this.maxBreadcrumbs);
    }
  }

  /**
   * Create a scope for isolated error tracking
   */
  withScope(callback: (scope: SentryScope) => void): void {
    const scope = new SentryScope();
    callback(scope);
  }

  /**
   * Flush pending events (for serverless environments)
   */
  async flush(timeout = 2000): Promise<boolean> {
    // In a real implementation, this would flush pending events
    return true;
  }

  /**
   * Check if Sentry is enabled
   */
  isActive(): boolean {
    return this.isEnabled;
  }

  private generateEventId(): string {
    return `evt_${Date.now().toString(36)}_${Math.random().toString(36).substring(2, 11)}`;
  }

  private logToSentry(type: string, data: Record<string, unknown>): void {
    // Placeholder for actual Sentry API call
    // In production with @sentry/nextjs, this would use the Sentry SDK
    logger.debug(`[Sentry ${type}]`, data);
  }
}

/**
 * Scope class for isolated error context
 */
class SentryScope {
  private tags: Record<string, string> = {};
  private extra: Record<string, unknown> = {};
  private user: SentryContext['user'] | null = null;
  private level: string = 'error';

  setTag(key: string, value: string): void {
    this.tags[key] = value;
  }

  setExtra(key: string, value: unknown): void {
    this.extra[key] = value;
  }

  setUser(user: SentryContext['user'] | null): void {
    this.user = user;
  }

  setLevel(level: string): void {
    this.level = level;
  }

  getContext(): SentryContext {
    return {
      user: this.user || undefined,
      tags: this.tags,
      extra: this.extra,
    };
  }
}

// Export singleton instance
export const sentry = new SentryHandler();

// Export for API error handling
export function captureApiError(error: Error, req?: { url?: string; method?: string }): string {
  return sentry.captureException(error, {
    tags: {
      api: 'true',
      path: req?.url || 'unknown',
      method: req?.method || 'unknown',
    },
  });
}

// Export types
export type { SentryContext, BreadcrumbData };
