/**
 * RPC Client Logger (Browser-Friendly)
 *
 * Auto-generated logging module for TypeScript RPC client.
 * Uses consola for beautiful browser console output.
 *
 * Generated by: django_ipc codegen
 */

import { createConsola, LogLevels, LogLevel } from "consola";

/**
 * Logger configuration
 */
export interface ClientLoggerConfig {
  /** Log level (0-5: silent, error, warn, info, debug, trace) */
  level?: LogLevel;
  /** Whether to log RPC calls */
  logRPCCalls?: boolean;
  /** Maximum number of logs to keep in memory */
  maxLogs?: number;
  /** Whether to save logs to sessionStorage (auto-clears on tab close) */
  useSessionStorage?: boolean;
  /** SessionStorage key prefix */
  storagePrefix?: string;
  /** Whether to send logs to server (optional) */
  sendToServer?: boolean;
  /** Server endpoint for logs (if sendToServer=true) */
  serverEndpoint?: string;
}

/**
 * Log entry structure
 */
interface LogEntry {
  timestamp: string;
  level: string;
  message: string;
  method?: string;
  params?: any;
  result?: any;
  duration_ms?: number;
  success?: boolean;
  correlation_id?: string;
  direction?: string;
  error?: any;
}

/**
 * RPC Client Logger with beautiful console output
 *
 * Features:
 * - Beautiful console output with consola (emoji, colors, grouping)
 * - In-memory log storage
 * - SessionStorage persistence (auto-clears on tab close)
 * - Optional server logging
 * - Automatic request/response tracking
 *
 * @example
 * ```typescript
 * import { ClientLogger } from './logger';
 *
 * const logger = new ClientLogger({
 *   level: 3, // INFO
 *   logRPCCalls: true,
 * });
 *
 * logger.info('Client connected');
 * logger.logRPCCall('create_user', {...}, {...}, 45.2, true);
 * ```
 */
export class ClientLogger {
  private config: Required<ClientLoggerConfig>;
  private consola: ReturnType<typeof createConsola>;
  private logs: LogEntry[] = [];

  constructor(config?: ClientLoggerConfig) {
    this.config = {
      level: 3, // INFO by default
      logRPCCalls: true,
      maxLogs: 1000,
      useSessionStorage: true,
      storagePrefix: "rpc_client_logs",
      sendToServer: false,
      serverEndpoint: "",
      ...config,
    };

    // Create consola instance with custom config
    this.consola = createConsola({
      level: this.config.level,
      formatOptions: {
        colors: true,
        compact: false,
        date: true,
      },
    });

    // Load logs from sessionStorage if enabled
    if (this.config.useSessionStorage) {
      this.loadFromSessionStorage();
    }
  }

  /**
   * Log debug message
   */
  debug(message: string, data?: any): void {
    this.consola.debug(message, data);
    this.saveLog("DEBUG", message, data);
  }

  /**
   * Log info message
   */
  info(message: string, data?: any): void {
    this.consola.info(message, data);
    this.saveLog("INFO", message, data);
  }

  /**
   * Log success message
   */
  success(message: string, data?: any): void {
    this.consola.success(message, data);
    this.saveLog("SUCCESS", message, data);
  }

  /**
   * Log warning message
   */
  warning(message: string, data?: any): void {
    this.consola.warn(message, data);
    this.saveLog("WARNING", message, data);
  }

  /**
   * Log error message
   */
  error(message: string, error?: Error | any, data?: any): void {
    if (error) {
      this.consola.error(message, error);
      this.saveLog("ERROR", message, { error, ...data });
    } else {
      this.consola.error(message, data);
      this.saveLog("ERROR", message, data);
    }
  }

  /**
   * Log complete RPC call (request + response)
   *
   * @param method - RPC method name
   * @param params - Request parameters
   * @param result - Response result
   * @param durationMs - Call duration in milliseconds
   * @param success - Whether call succeeded
   * @param correlationId - Correlation ID for tracking
   */
  logRPCCall(
    method: string,
    params: any,
    result: any,
    durationMs: number,
    success: boolean,
    correlationId?: string
  ): void {
    if (!this.config.logRPCCalls) {
      return;
    }

    const timing = `${durationMs.toFixed(1)}ms`;
    const cid = correlationId ? `[${correlationId}]` : "";

    if (success) {
      // Success - use success logger with grouping
      this.consola.success(`RPC ${cid} ${method} (${timing})`);

      // Create collapsed group
      console.groupCollapsed(`📦 Details`);
      console.log("Params:", params);
      console.log("Result:", result);
      console.groupEnd();
    } else {
      // Error - use error logger
      this.consola.error(`RPC ${cid} ${method} FAILED (${timing})`);

      console.groupCollapsed(`❌ Error Details`);
      console.log("Params:", params);
      console.log("Error:", result);
      console.groupEnd();
    }

    // Save to storage
    this.saveLog(success ? "RPC_SUCCESS" : "RPC_ERROR", `RPC: ${method}`, {
      method,
      params,
      result: success ? result : null,
      duration_ms: Math.round(durationMs * 100) / 100,
      success,
      correlation_id: correlationId,
      direction: "client->server",
    });
  }

  /**
   * Log RPC request
   */
  logRequest(method: string, params: any, correlationId?: string): void {
    if (!this.config.logRPCCalls) {
      return;
    }

    const cid = correlationId ? `[${correlationId}]` : "";
    this.consola.debug(`→ Request ${cid} ${method}`, params);

    this.saveLog("RPC_REQUEST", `Request: ${method}`, {
      method,
      params,
      correlation_id: correlationId,
      direction: "request",
    });
  }

  /**
   * Log RPC response
   */
  logResponse(
    method: string,
    result: any,
    durationMs: number,
    success: boolean,
    correlationId?: string
  ): void {
    if (!this.config.logRPCCalls) {
      return;
    }

    const cid = correlationId ? `[${correlationId}]` : "";
    const timing = `${durationMs.toFixed(1)}ms`;

    if (success) {
      this.consola.debug(`← Response ${cid} ${method} (${timing})`, result);
    } else {
      this.consola.error(`← Response ${cid} ${method} FAILED (${timing})`, result);
    }

    this.saveLog(success ? "RPC_RESPONSE" : "RPC_ERROR", `Response: ${method}`, {
      method,
      result: success ? result : null,
      duration_ms: Math.round(durationMs * 100) / 100,
      success,
      correlation_id: correlationId,
      direction: "response",
    });
  }

  /**
   * Save log entry to memory and storage
   */
  private saveLog(level: string, message: string, data?: any): void {
    const entry: LogEntry = {
      timestamp: new Date().toISOString(),
      level,
      message,
      ...data,
    };

    // Add to in-memory storage
    this.logs.push(entry);

    // Trim if exceeds max
    if (this.logs.length > this.config.maxLogs) {
      this.logs.shift();
    }

    // Save to sessionStorage
    if (this.config.useSessionStorage) {
      this.saveToSessionStorage();
    }

    // Send to server if enabled
    if (this.config.sendToServer && this.config.serverEndpoint) {
      this.sendToServer(entry);
    }
  }

  /**
   * Save logs to sessionStorage
   */
  private saveToSessionStorage(): void {
    try {
      // Keep only last 100 logs in sessionStorage
      const logsToSave = this.logs.slice(-100);
      sessionStorage.setItem(
        this.config.storagePrefix,
        JSON.stringify(logsToSave)
      );
    } catch (error) {
      console.warn("Failed to save logs to sessionStorage:", error);
    }
  }

  /**
   * Load logs from sessionStorage
   */
  private loadFromSessionStorage(): void {
    try {
      const stored = sessionStorage.getItem(this.config.storagePrefix);
      if (stored) {
        this.logs = JSON.parse(stored);
      }
    } catch (error) {
      console.warn("Failed to load logs from sessionStorage:", error);
    }
  }

  /**
   * Send log to server
   */
  private async sendToServer(entry: LogEntry): Promise<void> {
    try {
      await fetch(this.config.serverEndpoint, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify(entry),
      });
    } catch (error) {
      // Silent fail - don't spam console with logging errors
    }
  }

  /**
   * Get all logs
   */
  getLogs(): LogEntry[] {
    return [...this.logs];
  }

  /**
   * Get logs by method
   */
  getLogsByMethod(method: string): LogEntry[] {
    return this.logs.filter((log) => log.method === method);
  }

  /**
   * Get logs by correlation ID
   */
  getLogsByCorrelationId(correlationId: string): LogEntry[] {
    return this.logs.filter((log) => log.correlation_id === correlationId);
  }

  /**
   * Clear all logs
   */
  clearLogs(): void {
    this.logs = [];
    if (this.config.useSessionStorage) {
      sessionStorage.removeItem(this.config.storagePrefix);
    }
    this.consola.info("Logs cleared");
  }

  /**
   * Export logs as JSON
   */
  exportLogs(): string {
    return JSON.stringify(this.logs, null, 2);
  }

  /**
   * Download logs as file
   */
  downloadLogs(filename: string = "rpc-client-logs.json"): void {
    const blob = new Blob([this.exportLogs()], { type: "application/json" });
    const url = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = url;
    a.download = filename;
    a.click();
    URL.revokeObjectURL(url);
    this.consola.success(`Logs downloaded: ${filename}`);
  }

  /**
   * Print logs to console
   */
  printLogs(filter?: { method?: string; success?: boolean }): void {
    let logs = this.logs;

    if (filter?.method) {
      logs = logs.filter((log) => log.method === filter.method);
    }

    if (filter?.success !== undefined) {
      logs = logs.filter((log) => log.success === filter.success);
    }

    console.table(
      logs.map((log) => ({
        Time: new Date(log.timestamp).toLocaleTimeString(),
        Level: log.level,
        Method: log.method || "-",
        Duration: log.duration_ms ? `${log.duration_ms}ms` : "-",
        Success: log.success !== undefined ? (log.success ? "✅" : "❌") : "-",
        Message: log.message,
      }))
    );
  }
}

/**
 * Create a logger instance with default config
 */
export function createLogger(config?: ClientLoggerConfig): ClientLogger {
  return new ClientLogger(config);
}
