/**
 * Custom Pino transport for sending errors to Sentry
 *
 * This transport processes Pino log entries and sends error-level
 * logs to Sentry for error tracking and monitoring.
 */

import type { StructuredLog } from './logger';

export interface SentryTransportOptions {
  dsn?: string;
  environment?: string;
  sampleRate?: number;
  enabled?: boolean;
}

/**
 * Send log to Sentry
 * Only sends errors (level >= 50 in Pino)
 */
async function sendToSentry(log: StructuredLog): Promise<void> {
  const isDevelopment = process.env.NODE_ENV !== 'production';
  const sentryDsn = process.env.NEXT_PUBLIC_SENTRY_DSN;

  // Skip if Sentry not configured or in development
  if (!sentryDsn || isDevelopment) {
    return;
  }

  try {
    const sentryModuleName = '@sentry/nextjs';
    const Sentry = await import(/* webpackIgnore: true */ sentryModuleName) as {
      captureException: (error: Error, options?: {
        level?: string;
        extra?: Record<string, unknown>;
        tags?: Record<string, string>;
        contexts?: Record<string, unknown>;
      }) => void;
    };

    // Create error object
    const error = log.error
      ? new Error(log.error.message)
      : new Error(log.message);

    if (log.error?.stack) {
      error.stack = log.error.stack;
    }
    if (log.error?.name) {
      error.name = log.error.name;
    }

    // Prepare extra context
    const extra: Record<string, unknown> = {
      ...log.context,
    };

    if (log.requestId) {
      extra.requestId = log.requestId;
    }
    if (log.correlationId) {
      extra.correlationId = log.correlationId;
    }
    if (log.service) {
      extra.service = log.service;
    }

    // Set tags
    const tags: Record<string, string> = {
      level: log.level,
    };
    if (log.environment) {
      tags.environment = log.environment;
    }

    // Send to Sentry
    Sentry.captureException(error, {
      level: log.level === 'error' ? 'error' : 'warning',
      extra,
      tags,
      contexts: {
        log: {
          timestamp: log.timestamp,
          message: log.message,
        },
      },
    });
  } catch (err) {
    // Sentry is optional - don't throw if it fails
    console.error('Failed to send to Sentry:', err);
  }
}

/**
 * Process a Pino log entry and send to Sentry if appropriate
 */
export async function processSentryLog(
  logEntry: Record<string, unknown>
): Promise<void> {
  // Only send error and fatal levels to Sentry (50 and 60 in Pino)
  const level = logEntry.level as number;
  if (level < 50) {
    return;
  }

  // Convert Pino log to StructuredLog format
  const structuredLog: StructuredLog = {
    timestamp: new Date(logEntry.time as number).toISOString(),
    level: level >= 60 ? 'error' : 'error', // Map fatal to error
    message: (logEntry.msg as string) || '',
    context: {},
    service: (logEntry.service as string) || 'mawidi-site',
    environment: process.env.NODE_ENV,
  };

  // Extract context fields (level already used above, other fields excluded from context)
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  const { level: _level, time: _time, msg: _msg, pid: _pid, hostname: _hostname, ...context } = logEntry;
  structuredLog.context = context;

  // Extract error details if present
  if (logEntry.err) {
    const err = logEntry.err as {
      message?: string;
      stack?: string;
      type?: string;
      name?: string;
    };
    structuredLog.error = {
      message: err.message || '',
      stack: err.stack,
      name: err.name || err.type,
    };
  }

  // Extract request/correlation IDs
  if (logEntry.requestId) {
    structuredLog.requestId = logEntry.requestId as string;
  }
  if (logEntry.correlationId) {
    structuredLog.correlationId = logEntry.correlationId as string;
  }

  await sendToSentry(structuredLog);
}

/**
 * Create a Sentry transport stream for logging
 */
export function createSentryTransport() {
  return async function (source: AsyncIterable<string>) {
    for await (const line of source) {
      try {
        const logEntry = JSON.parse(line);
        await processSentryLog(logEntry);
      } catch (err) {
        // Ignore parsing errors - don't want to break logging
        console.error('Failed to parse Pino log for Sentry:', err);
      }
    }
  };
}
