import type { Database } from '@db/sqlite';
import * as colors from 'jsr:@std/fmt@^1.0.4/colors';
import * as log from 'jsr:@std/log';
import { DatabaseHandler } from './databaseLogger.ts';
import { getEveFilePath } from './files.ts';
export * as log from 'jsr:@std/log';

/**
 * Sanitizes data before logging to prevent accidental exposure of sensitive information
 * @param data The data to sanitize
 * @returns Sanitized data safe for logging
 */
function sanitizeForLogging(data: unknown): unknown {
  if (data === null || data === undefined || typeof data !== 'object') {
    return data;
  }

  if (data instanceof Uint8Array) {
    // Never log raw binary data that could contain keys
    return `[Uint8Array length=${data.length}]`;
  }

  if (Array.isArray(data)) {
    return data.map(sanitizeForLogging);
  }

  const sanitized: Record<string, unknown> = {};
  const sensitiveKeys = [
    'privatekey',
    'private_key',
    'privkey',
    'priv_key',
    'secretkey',
    'secret_key',
    'seckey',
    'sec_key',
    'password',
    'pass',
    'pwd',
    'token',
    'auth',
    'ccnprivatekey',
    'ccn_private_key',
    'ccnprivkey',
    'seed',
    'seedphrase',
    'seed_phrase',
    'mnemonic',
    'mnemonic_phrase',
    'mnemonic_phrase_words',
  ];

  for (const [key, value] of Object.entries(data as Record<string, unknown>)) {
    const lowerKey = key.toLowerCase();

    if (sensitiveKeys.some((sensitiveKey) => lowerKey.includes(sensitiveKey))) {
      sanitized[key] = '[REDACTED]';
    } else {
      sanitized[key] = sanitizeForLogging(value);
    }
  }

  return sanitized;
}

export async function setupLogger(db: Database | null) {
  const formatLevel = (level: number): string => {
    return (
      {
        10: colors.gray('[DEBUG]'),
        20: colors.green('[INFO] '),
        30: colors.yellow('[WARN] '),
        40: colors.red('[ERROR]'),
        50: colors.bgRed('[FATAL]'),
      }[level] || `[LVL${level}]`
    );
  };

  const levelName = (level: number): string => {
    return (
      {
        10: 'DEBUG',
        20: 'INFO',
        30: 'WARN',
        40: 'ERROR',
        50: 'FATAL',
      }[level] || `LVL${level}`
    );
  };

  const formatArg = (arg: unknown): string => {
    const sanitized = sanitizeForLogging(arg);
    if (typeof sanitized === 'object') return JSON.stringify(sanitized);
    return String(sanitized);
  };

  const handlers: Record<string, log.BaseHandler> = {
    console: new log.ConsoleHandler('DEBUG', {
      useColors: true,
      formatter: (record) => {
        const timestamp = new Date().toISOString();
        let msg = `${colors.dim(`[${timestamp}]`)} ${formatLevel(record.level)} ${record.msg}`;

        if (record.args.length > 0) {
          const args = record.args
            .map((arg, i) => `${colors.dim(`arg${i}:`)} ${formatArg(arg)}`)
            .join(' ');
          msg += ` ${colors.dim('|')} ${args}`;
        }

        return msg;
      },
    }),
    file: new log.FileHandler('DEBUG', {
      filename:
        Deno.env.get('LOG_FILE') || (await getEveFilePath('eve-logs.jsonl')),
      formatter: (record) => {
        const timestamp = new Date().toISOString();
        return JSON.stringify({
          timestamp,
          level: levelName(record.level),
          msg: record.msg,
          args: record.args.map(sanitizeForLogging),
        });
      },
    }),
  };
  if (db) {
    handlers.database = new DatabaseHandler('DEBUG', { db });
  }
  log.setup({
    handlers,
    loggers: {
      default: {
        level: 'DEBUG',
        handlers: ['console', 'file', 'database'],
      },
    },
  });
}