/**
 * Verbose-Logging-Toggle: console.log laesst sich global stummschalten.
 * console.warn/console.error bleiben immer an — Fehler will man immer sehen.
 *
 * Default: an (true). Toggle ueber Settings → Protokoll → Verbose Logging.
 * Beim Start wird der gespeicherte Wert geladen, vorher loggen wir normal.
 */

import AsyncStorage from '@react-native-async-storage/async-storage';
import { Platform, DeviceEventEmitter } from 'react-native';
import rvs from './rvs';

// Lokales Event damit die SettingsScreen Live Logs / Events Tabs
// auch das sehen was die App SELBST loggt (reportAppDebug/Error).
// Bisher gingen die nur via RVS an die Bridge. Lokal sichtbar = Mama-
// tauglich Debug ohne curl.
export const APP_LOG_EVENT = 'AriaLocalAppLog';

interface LocalLogEntry {
  ts: number;
  level: 'info' | 'warn' | 'error';
  scope: string;
  message: string;
}

export const VERBOSE_LOGGING_KEY = 'aria_verbose_logging';
// Eigener Toggle fuer Debug-Logs die ueber RVS an die Bridge gehen
// (/shared/logs/app.log → Diagnostic /api/app-log). Damit der Default-User
// nicht stuendlich Traffic + Disk-Schreiben hat, dieser ist DEFAULT AUS.
// Stefan schaltet's nur ein wenn er ein konkretes Problem debuggen muss.
export const DEBUG_LOGS_TO_BRIDGE_KEY = 'aria_debug_logs_to_bridge';

// Original-console.log retten, damit wir die Wrapper jederzeit wieder
// "scharf" stellen koennen (sonst waere ein Toggle-an nach -aus tot).
const originalLog = console.log.bind(console);
const noop = () => {};

let _verbose = true;
let _debugLogsToBridge = false;

function applyState(): void {
  console.log = _verbose ? originalLog : noop;
}

/** Wert aus AsyncStorage laden und anwenden. Beim App-Start aufrufen. */
export async function initLogger(): Promise<void> {
  try {
    const v = await AsyncStorage.getItem(VERBOSE_LOGGING_KEY);
    _verbose = v !== 'false'; // default: true
  } catch {}
  try {
    const d = await AsyncStorage.getItem(DEBUG_LOGS_TO_BRIDGE_KEY);
    _debugLogsToBridge = d === 'true'; // default: false
  } catch {}
  applyState();
}

export function isVerboseLogging(): boolean {
  return _verbose;
}

export function setVerboseLogging(verbose: boolean): void {
  _verbose = verbose;
  applyState();
  AsyncStorage.setItem(VERBOSE_LOGGING_KEY, String(verbose)).catch(() => {});
}

export function isDebugLogsToBridge(): boolean {
  return _debugLogsToBridge;
}

export function setDebugLogsToBridge(enabled: boolean): void {
  _debugLogsToBridge = enabled;
  AsyncStorage.setItem(DEBUG_LOGS_TO_BRIDGE_KEY, String(enabled)).catch(() => {});
}

// ─── App-Crash-Reporting via RVS ────────────────────────────────────
//
// Wenn die App crasht — egal ob React-Render-Fehler (ErrorBoundary) oder
// ungefangener JS-Error (ErrorUtils-Handler) — schicken wir den Crash
// als RVS-Message vom Typ "app_log" an die Bridge. Die schreibt in
// /shared/logs/app.log, sodass wir/Diagnostic die Crashes mitlesen
// koennen ohne ADB.

interface AppErrorEvent {
  scope: string;
  message: string;
  stack?: string;
  level?: 'error' | 'warn' | 'info';
}

let _reportingInstalled = false;

/** Schickt einen App-Fehler via RVS an die Bridge. */
export function reportAppError(ev: AppErrorEvent): void {
  const ts = Date.now();
  try {
    rvs.send('app_log' as any, {
      ts,
      platform: Platform.OS,
      level: ev.level || 'error',
      scope: ev.scope,
      message: ev.message,
      stack: (ev.stack || '').slice(0, 8000),
    });
  } catch {
    // RVS noch nicht connected — Fehler geht im console weiter.
  }
  // Lokal in den App-Logs-Tab emitten — Errors gehen IMMER durch
  // (unabhaengig vom Debug-Toggle).
  try {
    const entry: LocalLogEntry = {
      ts, level: ev.level || 'error', scope: ev.scope, message: ev.message,
    };
    DeviceEventEmitter.emit(APP_LOG_EVENT, entry);
  } catch {}
  // Plus lokal: console.error, damit Stefan's adb (wenn doch mal verfuegbar)
  // den Crash sieht.
  console.error(`[app-error scope=${ev.scope}]`, ev.message, '\n', ev.stack || '');
}

/** Schickt eine Debug-/Info-Message via RVS an die Bridge. Landet ebenfalls
 *  in /shared/logs/app.log — abrufbar via `curl /api/app-log?lines=N`.
 *  Im Gegensatz zu reportAppError: keine Stacktrace, level=info, kein
 *  console.error. Fuer Live-Diagnose im Hintergrund wenn ADB nicht da ist.
 *
 *  Nur aktiv wenn Settings → Protokoll → Debug-Logs an Bridge AN ist.
 *  Default aus damit Mama-Modus keine Disk-Schreiblast hat. Error-Reports
 *  (reportAppError) gehen weiterhin IMMER durch. */
export function reportAppDebug(scope: string, message: string): void {
  if (!_debugLogsToBridge) return;
  const ts = Date.now();
  const trimmed = String(message).slice(0, 2000);
  try {
    rvs.send('app_log' as any, {
      ts,
      platform: Platform.OS,
      level: 'info',
      scope,
      message: trimmed,
    });
  } catch {}
  // Plus lokal in den App-Logs-Tab emitten — damit Stefan in der App
  // selbst (Settings → Protokoll → Live Logs) sieht was passiert,
  // ohne curl gegen Bridge.
  try {
    const entry: LocalLogEntry = { ts, level: 'info', scope, message: trimmed };
    DeviceEventEmitter.emit(APP_LOG_EVENT, entry);
  } catch {}
}

/** Installiert einen globalen JS-Error-Handler der ungefangene Errors via
 *  RVS an die Bridge schickt. Beim App-Start aufrufen. */
export function installGlobalCrashReporter(): void {
  if (_reportingInstalled) return;
  _reportingInstalled = true;
  try {
    const g: any = global as any;
    const prev = g.ErrorUtils?.getGlobalHandler?.();
    g.ErrorUtils?.setGlobalHandler?.((err: any, isFatal: boolean) => {
      reportAppError({
        scope: isFatal ? 'global-fatal' : 'global-nonfatal',
        message: (err && err.message) || String(err),
        stack: err && err.stack,
      });
      // Original-Handler weiterhin aufrufen damit React-Native das System-
      // Crash-Overlay zeigt (im Dev-Build) bzw. in Production sauber stirbt.
      if (typeof prev === 'function') {
        try { prev(err, isFatal); } catch {}
      }
    });
    // unhandled Promise-Rejections — manche RN-Versionen haben das nicht
    // automatisch im ErrorUtils.
    g.HermesInternal?.enablePromiseRejectionTracker?.({
      allRejections: true,
      onUnhandled: (id: number, err: any) => {
        reportAppError({
          scope: 'promise-unhandled',
          level: 'warn',
          message: (err && err.message) || String(err),
          stack: err && err.stack,
        });
      },
    });
  } catch {
    // ErrorUtils nicht da → nix machen
  }
}
