import { isTauri } from '../mock-tauri'
import { TOKEN_REDACTION, isSensitiveDiagnosticKey, sanitizeDiagnosticText } from './sensitiveTextRedaction'

type DiagnosticLevel = 'error' | 'warn'

interface DiagnosticEntry {
  level: DiagnosticLevel
  message: string
}

interface DiagnosticBundleContext {
  buildNumber?: string
  releaseChannel?: string | null
}

const MAX_DIAGNOSTICS = 8

let recentDiagnostics: DiagnosticEntry[] = []
let stopCapture: (() => void) | null = null

function truncate(input: string, maxLength = 240): string {
  if (input.length <= maxLength) return input
  return `${input.slice(0, maxLength - 1)}…`
}

function sanitizeText(input: string): string {
  return truncate(sanitizeDiagnosticText({ text: input }))
}

function safeSerialize(value: unknown): string {
  if (value instanceof Error) {
    return `${value.name}: ${value.message}`
  }

  if (typeof value === 'string') {
    return value
  }

  if (typeof value === 'number' || typeof value === 'boolean') {
    return String(value)
  }

  if (value == null) {
    return String(value)
  }

  try {
    return JSON.stringify(value, (key, nestedValue) => {
      if (typeof nestedValue === 'string') {
        return isSensitiveDiagnosticKey({ text: key }) ? TOKEN_REDACTION : truncate(nestedValue, 120)
      }
      return nestedValue
    })
  } catch {
    return Object.prototype.toString.call(value)
  }
}

function recordDiagnostic(level: DiagnosticLevel, values: unknown[]): void {
  const message = sanitizeText(values.map((value) => safeSerialize(value)).join(' '))
  if (!message) return

  recentDiagnostics = [
    ...recentDiagnostics.slice(-(MAX_DIAGNOSTICS - 1)),
    { level, message },
  ]
}

function resolveRuntime(): string {
  if (typeof window === 'undefined') return 'unknown'
  return isTauri() ? 'tauri' : 'browser'
}

function resolvePlatform(): string {
  if (typeof navigator === 'undefined') return 'unknown'
  return sanitizeText(navigator.platform || 'unknown')
}

function resolveUserAgent(): string {
  if (typeof navigator === 'undefined') return 'unknown'
  return sanitizeText(navigator.userAgent || 'unknown')
}

export function startFeedbackDiagnosticsCapture(): () => void {
  if (stopCapture || typeof window === 'undefined') {
    return stopCapture ?? (() => {})
  }

  const originalError = console.error
  const originalWarn = console.warn

  console.error = (...args: Parameters<typeof console.error>) => {
    recordDiagnostic('error', args)
    originalError(...args)
  }

  console.warn = (...args: Parameters<typeof console.warn>) => {
    recordDiagnostic('warn', args)
    originalWarn(...args)
  }

  const handleError = (event: ErrorEvent) => {
    recordDiagnostic('error', [event.error ?? event.message ?? 'Unhandled window error'])
  }

  const handleUnhandledRejection = (event: PromiseRejectionEvent) => {
    recordDiagnostic('error', ['Unhandled rejection:', event.reason])
  }

  window.addEventListener('error', handleError)
  window.addEventListener('unhandledrejection', handleUnhandledRejection)

  stopCapture = () => {
    console.error = originalError
    console.warn = originalWarn
    window.removeEventListener('error', handleError)
    window.removeEventListener('unhandledrejection', handleUnhandledRejection)
    stopCapture = null
  }

  return stopCapture
}

export function buildSanitizedDiagnosticBundle({
  buildNumber,
  releaseChannel,
}: DiagnosticBundleContext): string {
  const lines = [
    'Tolaria sanitized diagnostics',
    `Generated: ${new Date().toISOString()}`,
    `Build: ${buildNumber ?? 'unknown'}`,
    `Release channel: ${releaseChannel ?? 'stable'}`,
    `Runtime: ${resolveRuntime()}`,
    `Platform: ${resolvePlatform()}`,
    `User agent: ${resolveUserAgent()}`,
    '',
    'Recent diagnostics:',
  ]

  if (recentDiagnostics.length === 0) {
    lines.push('No safe recent diagnostics were available.')
  } else {
    for (const entry of recentDiagnostics) {
      lines.push(`- [${entry.level}] ${entry.message}`)
    }
  }

  lines.push('')
  lines.push('Notes: paths and token-like strings are redacted. This bundle is sanitized and optional.')

  return lines.join('\n')
}

export function __resetFeedbackDiagnosticsForTest(): void {
  stopCapture?.()
  recentDiagnostics = []
}
