import { LogLevel } from './log-level.enum';
import { Type } from '@angular/core';

/**
 * Represents a destination where log messages are sent.
 * Implement this interface to create custom logging destinations like
 * console logging, remote logging services, or file logging.
 *
 * @example
 * ```typescript
 * @Injectable()
 * export class CustomLogSink implements Sink {
 *   log(
 *     level: LogLevel,
 *     message: string,
 *     context?: LoggerContext,
 *     error?: Error
 *   ): void {
 *     // Custom logging implementation
 *     if (level === LogLevel.Error) {
 *       // Send to monitoring service
 *       this.monitoringService.reportError(message, error, context);
 *     }
 *   }
 * }
 * ```
 */
export interface Sink {
  /**
   * Method called by the LoggingService to send a log entry to this sink.
   *
   * @param level - The severity level of the log message
   * @param message - The main log message content
   * @param context - Optional structured data or metadata about the log event
   * @param error - Optional error object when logging errors
   */
  log(
    level: LogLevel,
    message: string,
    context?: LoggerContext,
    error?: Error,
  ): void;
}

/**
 * A factory function that creates a logging sink function.
 * Useful when the sink needs access to injected dependencies or
 * requires initialization logic.
 *
 * @returns A function matching the Sink.log method signature
 *
 * @example
 * ```typescript
 * export const httpLogSink: SinkFn = () => {
 *   const http = inject(HttpClient);
 *   const config = inject(ConfigService);
 *
 *   return (level, message, context?, error?) => {
 *     http.post(config.loggingEndpoint, {
 *       level,
 *       message,
 *       context,
 *       error: error && {
 *         name: error.name,
 *         message: error.message,
 *         stack: error.stack
 *       }
 *     }).subscribe();
 *   };
 * };
 * ```
 */
export type SinkFn = () => (
  level: LogLevel,
  message: string,
  context?: LoggerContext,
  error?: Error,
) => void;

/**
 * Configuration options for the logging service.
 * Used to set up the logging behavior during application initialization.
 */
export interface LoggingConfig {
  /** The minimum log level to process. Messages below this level are ignored. */
  level: LogLevel;

  /**
   * An array of logging destinations where messages will be sent.
   * Can be sink instances, classes, or factory functions.
   */
  sinks: (Sink | SinkFn | Type<Sink>)[];

  /**
   * Optional global context included with every log message.
   * Useful for adding application-wide metadata like version or environment.
   */
  context?: LoggerContext;
}

/**
 * Represents the public API for logging operations.
 * This interface is returned by the logger factory and provides
 * methods for logging at different severity levels.
 */
export interface LoggerApi {
  /**
   * Logs a trace message with optional context.
   * Use for fine-grained debugging information.
   */
  trace(message: string, context?: () => LoggerContext): void;

  /**
   * Logs a debug message with optional context.
   * Use for development-time debugging information.
   */
  debug(message: string, context?: () => LoggerContext): void;

  /**
   * Logs an info message with optional context.
   * Use for general runtime information.
   */
  info(message: string, context?: () => LoggerContext): void;

  /**
   * Logs a warning message with optional context.
   * Use for potentially harmful situations.
   */
  warn(message: string, context?: () => LoggerContext): void;

  /**
   * Logs an error message with an optional error object and context.
   * Use for error conditions that affect functionality.
   *
   * @param message - The error message to log
   * @param error - Optional error object that caused this error condition
   * @param context - Optional context data associated with the error
   */
  error(message: string, error?: unknown, context?: () => LoggerContext): void;
}

/**
 * Represents context data associated with a log message.
 * Context allows adding structured metadata to log messages,
 * making them more informative and easier to filter/analyze.
 *
 * @example
 * ```typescript
 * // Component context
 * const context: LoggerContext = {
 *   component: 'UserProfile',
 *   userId: '12345',
 *   action: 'save'
 * };
 *
 * // Error context
 * const errorContext: LoggerContext = {
 *   operationId: 'op-123',
 *   attemptNumber: 3,
 *   inputData: { ... }
 * };
 * ```
 */
export interface LoggerContext {
  [key: string]: unknown;
}

export type LoggerContextFn = () => LoggerContext;

export type MaybeLoggerContextFn = LoggerContext | LoggerContextFn;
