/**
 * Enhanced logger with self-contained database logging
 *
 * Provides comprehensive logging with console and database output.
 * Supports configurable log levels via VITE_LOG_LEVEL environment variable.
 *
 * @author Matthew Raymer
 * @version 2.1.0
 * @since 2025-01-25
 */

import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";

const _memoryLogs: string[] = [];

export function appendToMemoryLogs(message: string): void {
  _memoryLogs.push(`${new Date().toISOString()}: ${message}`);
  if (_memoryLogs.length > 1000) {
    _memoryLogs.splice(0, _memoryLogs.length - 1000);
  }
}

export function getMemoryLogs(): string[] {
  return [..._memoryLogs];
}

export function safeStringify(obj: unknown) {
  const seen = new WeakSet();

  return JSON.stringify(obj, (_key, value) => {
    if (typeof value === "object" && value !== null) {
      if (seen.has(value)) {
        return "[Circular]";
      }
      seen.add(value);
    }

    if (typeof value === "function") {
      return `[Function: ${value.name || "anonymous"}]`;
    }

    return value;
  });
}

// Determine if we should suppress verbose logging (for Electron)
const isElectron = process.env.VITE_PLATFORM === "electron";
const isProduction = process.env.NODE_ENV === "production";

// Log level configuration via environment variable
const LOG_LEVELS = {
  error: 0,
  warn: 1,
  info: 2,
  debug: 3,
} as const;

type LogLevel = keyof typeof LOG_LEVELS;

// Parse VITE_LOG_LEVEL environment variable
const getLogLevel = (): LogLevel => {
  const envLogLevel = process.env.VITE_LOG_LEVEL?.toLowerCase();

  if (envLogLevel && envLogLevel in LOG_LEVELS) {
    return envLogLevel as LogLevel;
  }

  // Default log levels based on environment
  if (isProduction && !isElectron) {
    return "warn"; // Production web: warnings and errors only
  } else if (isElectron) {
    return "error"; // Electron: errors only
  } else {
    return "info"; // Development/Capacitor: info and above
  }
};

const currentLogLevel = getLogLevel();
const currentLevelValue = LOG_LEVELS[currentLogLevel];

// Helper function to check if a log level should be displayed
const shouldLog = (level: LogLevel): boolean => {
  return LOG_LEVELS[level] <= currentLevelValue;
};

// Track initialization state to prevent circular dependencies
let isInitializing = true;

// Mark initialization as complete after a delay to allow all services to start
setTimeout(() => {
  isInitializing = false;
}, 2000); // 2 second delay to allow all services to initialize

// Function to check if we should skip database logging during initialization
function shouldSkipDatabaseLogging(message: string): boolean {
  // Skip during initialization phase
  if (isInitializing) {
    return true;
  }

  // Skip specific initialization-related messages even after initialization
  const initializationMessages = [
    "[PlatformServiceFactory]",
    "[SQLWorker]",
    "[WebPlatformService]",
    "[CapacitorPlatformService]",
    "[CapacitorMigration]",
    "[DB-Integrity]",
    "[Migration]",
    "[IndexedDBMigrationService]",
    "Creating singleton instance",
    "Worker loaded",
    "Worker initialized",
    "Platform service",
  ];

  return initializationMessages.some((pattern) => message.includes(pattern));
}

// Self-contained database logging function
async function logToDatabase(
  message: string,
  level: string = "info",
): Promise<void> {
  // Prevent infinite logging loops
  if (isInitializing || shouldSkipDatabaseLogging(message)) {
    return;
  }

  try {
    const platform = PlatformServiceFactory.getInstance();
    const todayKey = new Date().toDateString();

    await platform.dbExec("INSERT INTO logs (date, message) VALUES (?, ?)", [
      todayKey,
      `[${level.toUpperCase()}] ${message}`,
    ]);
  } catch (error) {
    // Fallback to console if database logging fails
    // eslint-disable-next-line no-console
    console.error(`[Logger] Database logging failed: ${error}`);
  }
}

// Enhanced logger with self-contained database methods and log level control
export const logger = {
  debug: (message: string, ...args: unknown[]) => {
    // Debug logs only show if VITE_LOG_LEVEL allows it
    if (shouldLog("debug")) {
      // eslint-disable-next-line no-console
      console.debug(message, ...args);
    }
    // Don't log debug messages to database to reduce noise
  },

  log: (message: string, ...args: unknown[]) => {
    // Regular logs - show if VITE_LOG_LEVEL allows info level
    if (shouldLog("info")) {
      // eslint-disable-next-line no-console
      console.log(message, ...args);
    }

    // Database logging
    const argsString = args.length > 0 ? " - " + safeStringify(args) : "";
    logToDatabase(message + argsString, "info");
  },

  info: (message: string, ...args: unknown[]) => {
    if (shouldLog("info")) {
      // eslint-disable-next-line no-console
      console.info(message, ...args);
    }

    // Database logging
    const argsString = args.length > 0 ? " - " + safeStringify(args) : "";
    logToDatabase(message + argsString, "info");
  },

  warn: (message: string, ...args: unknown[]) => {
    if (shouldLog("warn")) {
      // eslint-disable-next-line no-console
      console.warn(message, ...args);
    }

    // Database logging
    const argsString = args.length > 0 ? " - " + safeStringify(args) : "";
    logToDatabase(message + argsString, "warn");
  },

  error: (message: string, ...args: unknown[]) => {
    if (shouldLog("error")) {
      // eslint-disable-next-line no-console
      console.error(message, ...args);
    }

    // Database logging
    const messageString = safeStringify(message);
    const argsString = args.length > 0 ? safeStringify(args) : "";
    logToDatabase(messageString + argsString, "error");
  },

  // New database-focused methods (self-contained)
  toDb: async (message: string, level?: string): Promise<void> => {
    await logToDatabase(message, level || "info");
  },

  toConsoleAndDb: async (message: string, isError = false): Promise<void> => {
    // Console output based on log level
    if (isError && shouldLog("error")) {
      // eslint-disable-next-line no-console
      console.error(message);
    } else if (!isError && shouldLog("info")) {
      // eslint-disable-next-line no-console
      console.log(message);
    }
    // Database output
    await logToDatabase(message, isError ? "error" : "info");
  },

  // Component context methods
  withContext: (componentName?: string) => ({
    log: (message: string, level?: string) =>
      logToDatabase(`[${componentName}] ${message}`, level),
    error: (message: string) =>
      logToDatabase(`[${componentName}] ${message}`, "error"),
  }),

  // Log level information methods
  getCurrentLevel: (): LogLevel => currentLogLevel,
  getCurrentLevelValue: (): number => currentLevelValue,
  isLevelEnabled: (level: LogLevel): boolean => shouldLog(level),
  getAvailableLevels: (): LogLevel[] => Object.keys(LOG_LEVELS) as LogLevel[],
};

// Function to manually mark initialization as complete
export function markInitializationComplete(): void {
  isInitializing = false;
}

// Function to check initialization status
export function isInitializationPhase(): boolean {
  return isInitializing;
}

// Add CommonJS export for Electron
if (typeof module !== "undefined" && module.exports) {
  module.exports = {
    logger,
    markInitializationComplete,
    isInitializationPhase,
  };
}

// Add default export for ESM
export default { logger, markInitializationComplete, isInitializationPhase };
