/**
 * Shared Sentry configuration constants.
 *
 * Used by both main and renderer process init modules.
 * Does NOT resolve DSN - each process does that with its own env access
 * (main: process.env, renderer: import.meta.env).
 */

// eslint-disable-next-line @typescript-eslint/naming-convention -- Vite `define` injects this global
declare const __APP_VERSION__: string;

/** Release identifier injected at build time via Vite `define`. */
export const SENTRY_RELEASE =
  typeof __APP_VERSION__ === 'string' ? `agent-teams-ai@${__APP_VERSION__}` : undefined;

/** Environment derived from Node/Vite mode. */
export const SENTRY_ENVIRONMENT =
  process.env.NODE_ENV === 'production' ? 'production' : 'development';

/** Performance trace sample rate (production: 10%, dev: 100%). */
export const TRACES_SAMPLE_RATE = process.env.NODE_ENV === 'production' ? 0.1 : 1.0;

/** Validate that a string looks like a Sentry DSN. */
export function isValidDsn(dsn: string | undefined): dsn is string {
  return typeof dsn === 'string' && dsn.length > 0 && dsn.startsWith('https://');
}

const REDACTED = '[redacted]';
const MAX_REDACTION_DEPTH = 8;
const SENSITIVE_KEY_PATTERN =
  /(token|secret|authorization|cookie|email|account|clientid|project|repo|path|cwd|teamname|sessionid|taskid|username|user_name)/i;

const SENSITIVE_STRING_PATTERNS: Array<[RegExp, string]> = [
  [/\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi, REDACTED],
  [/\b[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\b/gi, REDACTED],
  [/\b(?:sk|pk|rk|ghp|gho|github_pat|xoxb|xoxp|ya29)[A-Za-z0-9_\-]{12,}\b/g, REDACTED],
  [/\/Users\/[^/\s"'`]+(?:\/[^\s"'`]+)*/g, '/Users/[redacted]/[redacted-path]'],
  [/\/home\/[^/\s"'`]+(?:\/[^\s"'`]+)*/g, '/home/[redacted]/[redacted-path]'],
  [/([A-Za-z]:\\Users\\)[^\\\s"'`]+(?:\\[^\\\s"'`]+)*/g, '$1[redacted]\\[redacted-path]'],
];

const UNSAFE_SENTRY_INTEGRATION_NAMES = new Set([
  'AdditionalContext',
  'Breadcrumbs',
  'BrowserSession',
  'ChildProcess',
  'Console',
  'ContextLines',
  'CultureContext',
  'ElectronBreadcrumbs',
  'ElectronContext',
  'ElectronNet',
  'EventLoopBlockRenderer',
  'GpuContext',
  'HttpContext',
  'LocalVariables',
  'NativeNodeFetch',
  'NodeContext',
  'NodeFetch',
  'PreloadInjection',
  'RendererEventLoopBlock',
  'RendererProfiling',
  'Screenshots',
  'SentryMinidump',
  'StartupTracing',
]);

interface SentryIntegrationLike {
  name?: string;
}

export function filterSafeSentryIntegrations<TIntegration extends SentryIntegrationLike>(
  integrations: TIntegration[]
): TIntegration[] {
  return integrations.filter(
    (integration) => !integration.name || !UNSAFE_SENTRY_INTEGRATION_NAMES.has(integration.name)
  );
}

function redactSentryString(value: string): string {
  return SENSITIVE_STRING_PATTERNS.reduce(
    (current, [pattern, replacement]) => current.replace(pattern, replacement),
    value
  );
}

function redactSentryValue(value: unknown, depth: number, seen: WeakSet<object>): unknown {
  if (typeof value === 'string') {
    return redactSentryString(value);
  }

  if (typeof value !== 'object' || value === null) {
    return value;
  }

  if (depth >= MAX_REDACTION_DEPTH || seen.has(value)) {
    return REDACTED;
  }

  seen.add(value);

  if (Array.isArray(value)) {
    return value.map((entry) => redactSentryValue(entry, depth + 1, seen));
  }

  const redacted: Record<string, unknown> = {};
  for (const [key, entry] of Object.entries(value)) {
    redacted[key] = SENSITIVE_KEY_PATTERN.test(key)
      ? REDACTED
      : redactSentryValue(entry, depth + 1, seen);
  }
  return redacted;
}

export function redactSentryEvent(event: unknown): unknown {
  return redactSentryValue(event, 0, new WeakSet<object>());
}
