/**
 * DC-071: Error tracking integration framework
 *
 * Provides an opt-in error tracking interface that can forward uncaught
 * errors to external services (Sentry, Bugsnag, etc.) when configured.
 *
 * In production, set ERROR_TRACKING_DSN environment variable to enable.
 * Without a DSN, errors are logged normally but not forwarded.
 *
 * Usage:
 *   const { errorTracker } = require('./utilities/error-tracker');
 *   errorTracker.init({ dsn: process.env.ERROR_TRACKING_DSN, release: '1.15.0' });
 *   errorTracker.capture(error, { extra: { route: req.path } });
 */

const os = require('os');

class ErrorTracker {
  constructor() {
    this.dsn = null;
    this.release = null;
    this.enabled = false;
    this.pendingFlush = Promise.resolve();
  }

  /**
   * Initialize the error tracker.
   * If no DSN is provided, tracking is disabled (errors still log normally).
   */
  init({ dsn, release, environment } = {}) {
    this.dsn = dsn || process.env.ERROR_TRACKING_DSN;
    this.release = release || process.env.npm_package_version || 'unknown';
    this.environment = environment || process.env.NODE_ENV || 'production';
    this.enabled = !!this.dsn;
    return this.enabled;
  }

  /**
   * Capture an error and forward to the tracking service.
   * Non-blocking — swallows network errors silently.
   */
  capture(error, context = {}) {
    if (!this.enabled || !error) return;

    const payload = {
      event_id: `${Date.now()}-${Math.random().toString(36).slice(2, 10)}`,
      timestamp: new Date().toISOString(),
      platform: 'node',
      level: 'error',
      release: this.release,
      environment: this.environment,
      message: error.message || String(error),
      stacktrace: error.stack || '',
      exception: {
        type: error.constructor.name,
        value: error.message,
      },
      tags: {
        hostname: os.hostname(),
        node_version: process.version,
        ...context.tags,
      },
      extra: {
        pid: process.pid,
        memory: process.memoryUsage().rss,
        uptime: process.uptime(),
        ...context.extra,
      },
      request: context.request || undefined,
      user: context.user || undefined,
    };

    // Fire-and-forget — don't block the event loop
    this.pendingFlush = this._send(payload).catch(() => {
      // Silent failure — tracking errors should never crash the app
    });

    return payload.event_id;
  }

  /**
   * Capture a message (not an error) at the specified level.
   */
  captureMessage(message, level = 'info', context = {}) {
    if (!this.enabled) return;
    return this.capture(
      Object.assign(new Error(message), { stack: '' }),
      { ...context, tags: { ...context.tags, level } }
    );
  }

  /**
   * Send the payload to the tracking service DSN.
   * Currently implements the Sentry envelope format.
   */
  async _send(payload) {
    if (!this.dsn) return;

    const url = new URL(this.dsn);
    const projectId = url.pathname.replace(/^\//, '');
    const apiKey = url.username;
    const ingestUrl = `${url.protocol}//${url.host}/api/${projectId}/store/`;

    const body = JSON.stringify(payload);

    const controller = new AbortController();
    const timeout = setTimeout(() => controller.abort(), 5000);

    try {
      const response = await fetch(ingestUrl, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-Sentry-Auth': `Sentry sentry_key=${apiKey}`,
        },
        body,
        signal: controller.signal,
      });

      if (!response.ok) {
        // Non-OK response — silently ignore
      }
    } finally {
      clearTimeout(timeout);
    }
  }

  /**
   * Wait for all pending events to flush.
   */
  async flush(timeoutMs = 2000) {
    await Promise.race([
      this.pendingFlush,
      new Promise(resolve => setTimeout(resolve, timeoutMs)),
    ]);
  }

  /**
   * Express error-handling middleware that captures errors before
   * forwarding to the next error handler.
   */
  middleware() {
    return (err, req, res, next) => {
      this.capture(err, {
        request: {
          url: req.url,
          method: req.method,
          headers: req.headers,
        },
        extra: {
          requestId: req.id,
          path: req.path,
        },
      });
      next(err);
    };
  }
}

module.exports = new ErrorTracker();
