import type { LoggingConfig, LoggerTransport } from './types';

// Check if we're in a browser environment
const isBrowser = typeof window !== 'undefined';

// Browser-compatible logger interface
interface BrowserLogger {
  info: (msg: string, ...args: any[]) => void;
  error: (msg: string, ...args: any[]) => void;
  warn: (msg: string, ...args: any[]) => void;
  debug: (msg: string, ...args: any[]) => void;
  child: (obj: any) => BrowserLogger;
}

let logger: any;

// Create a browser-compatible console logger
function createBrowserLogger(name: string = 'passkey-kit'): BrowserLogger {
  const prefix = `[${name}]`;
  
  return {
    info: (msg: string, ...args: any[]) => console.info(prefix, msg, ...args),
    error: (msg: string, ...args: any[]) => console.error(prefix, msg, ...args),
    warn: (msg: string, ...args: any[]) => console.warn(prefix, msg, ...args),
    debug: (msg: string, ...args: any[]) => console.debug(prefix, msg, ...args),
    child: (obj: any) => createBrowserLogger(`${name}:${Object.keys(obj).join(':')}`)
  };
}

function isPinoLogger(obj: any): boolean {
  return obj && 
    typeof obj === 'object' &&
    typeof obj.info === 'function' && 
    typeof obj.error === 'function' &&
    typeof obj.warn === 'function' &&
    typeof obj.debug === 'function' &&
    typeof obj.child === 'function';
}

export class LoggingService {
  static async init(config: LoggingConfig | any) {
    if (isPinoLogger(config)) {
      logger = config;
      return;
    }

    // Always use browser logger first as fallback
    logger = createBrowserLogger(config.name || 'passkey-kit');

    // Only try pino in Node.js environment and if it's available
    if (!isBrowser) {
      try {
        // Check if pino is available without importing it
        const pinoModule = await import('pino').catch(() => null);
        if (!pinoModule) return;

        const prettyModule = await import('pino-pretty').catch(() => null);
        const { Transform } = await import('stream').catch(() => ({ Transform: null }));

        if (pinoModule && prettyModule && Transform) {
          const pinoInstance = pinoModule.default || pinoModule;
          const prettyInstance = prettyModule.default || prettyModule;

          const streams: any[] = [];
          const level = config.level || 'info';
          const prettyStream: any = prettyInstance({ colorize: true });
          streams.push({ stream: prettyStream, level });

          Object.entries(config.transports || {}).forEach(([, stream]) => {
            streams.push({ stream, level });
          });

          logger = pinoInstance({ name: config.name || 'passkey-kit', level }, pinoInstance.multistream(streams));
        }
      } catch (error) {
        // Keep browser logger fallback
      }
    }
  }

  static get(): any {
    if (!logger) {
      logger = createBrowserLogger('passkey-kit');
      
      // Only try pino in Node.js environment
      if (!isBrowser) {
        import('pino').then(async (pinoModule) => {
          try {
            const pinoInstance = pinoModule.default || pinoModule;
            const prettyModule = await import('pino-pretty');
            const prettyInstance = prettyModule.default || prettyModule;
            
            logger = pinoInstance({ name: 'passkey-kit' }, pinoInstance.multistream([
              { stream: prettyInstance({ colorize: true }) }
            ]));
          } catch (error) {
            // Keep existing browser logger
          }
        }).catch(() => {
          // Keep existing browser logger
        });
      }
    }
    return logger;
  }
}

export function createCustomTransport(transform: any): LoggerTransport {
  if (isBrowser) {
    // In browser, return a simple writable stream-like object
    return {
      write: (chunk: any) => console.log(chunk),
      retrieveLogs: () => {
        throw new Error('retrieveLogs not implemented for browser transport');
      }
    } as LoggerTransport;
  }
  
  const transport = transform as LoggerTransport;
  
  // Add optional retrieveLogs method if not present
  if (!transport.retrieveLogs) {
    transport.retrieveLogs = () => {
      throw new Error('retrieveLogs not implemented for this transport');
    };
  }
  
  return transport;
}
