import { 
  PlatformError, 
  ValidationError, 
  NetworkError, 
  ResourceError, 
  OperationError
} from './base.errors.js';
import type { IErrorContext } from './base.errors.js';

import {
  EMAIL_SERVICE_ERROR,
  EMAIL_TEMPLATE_ERROR,
  EMAIL_VALIDATION_ERROR,
  EMAIL_SEND_ERROR,
  EMAIL_RECEIVE_ERROR,
  EMAIL_ATTACHMENT_ERROR,
  EMAIL_PARSE_ERROR,
  EMAIL_RATE_LIMIT_EXCEEDED
} from './error.codes.js';

/**
 * Base class for all email service related errors
 */
export class EmailServiceError extends OperationError {
  /**
   * Creates a new email service error
   * 
   * @param message Error message
   * @param context Additional context
   */
  constructor(
    message: string,
    context: IErrorContext = {}
  ) {
    super(message, EMAIL_SERVICE_ERROR, context);
  }
}

/**
 * Error class for email template errors
 */
export class EmailTemplateError extends OperationError {
  /**
   * Creates a new email template error
   * 
   * @param message Error message
   * @param context Additional context
   */
  constructor(
    message: string,
    context: IErrorContext = {}
  ) {
    super(message, EMAIL_TEMPLATE_ERROR, context);
  }
}

/**
 * Error class for email validation errors
 */
export class EmailValidationError extends ValidationError {
  /**
   * Creates a new email validation error
   * 
   * @param message Error message
   * @param context Additional context
   */
  constructor(
    message: string,
    context: IErrorContext = {}
  ) {
    super(message, EMAIL_VALIDATION_ERROR, context);
  }
}

/**
 * Error class for email sending errors
 */
export class EmailSendError extends OperationError {
  /**
   * Creates a new email send error
   * 
   * @param message Error message
   * @param context Additional context
   */
  constructor(
    message: string,
    context: IErrorContext = {}
  ) {
    super(message, EMAIL_SEND_ERROR, context);
  }

  /**
   * Creates an instance for a permanently failed send
   * 
   * @param message Error message
   * @param context Additional context
   */
  public static permanent(
    message: string,
    context: IErrorContext = {}
  ): EmailSendError {
    return new EmailSendError(`Permanent send failure: ${message}`, {
      ...context,
      data: {
        ...context.data,
        permanent: true
      },
      userMessage: 'The email could not be delivered due to a permanent failure.'
    });
  }

  /**
   * Creates an instance for a temporary failed send
   * 
   * @param message Error message
   * @param maxRetries Maximum number of retries
   * @param currentRetry Current retry count
   * @param retryDelay Delay between retries in ms
   * @param context Additional context
   */
  public static temporary(
    message: string,
    maxRetries: number = 3,
    currentRetry: number = 0,
    retryDelay: number = 60000,
    context: IErrorContext = {}
  ): EmailSendError {
    const error = new EmailSendError(`Temporary send failure: ${message}`, {
      ...context,
      data: {
        ...context.data,
        permanent: false
      },
      userMessage: 'The email delivery failed temporarily. It will be retried.'
    });
    
    return error.withRetry(maxRetries, currentRetry, retryDelay) as EmailSendError;
  }

  /**
   * Check if this is a permanent send failure
   */
  public isPermanent(): boolean {
    return !!this.context.data?.permanent;
  }
}

/**
 * Error class for email receiving errors
 */
export class EmailReceiveError extends OperationError {
  /**
   * Creates a new email receive error
   * 
   * @param message Error message
   * @param context Additional context
   */
  constructor(
    message: string,
    context: IErrorContext = {}
  ) {
    super(message, EMAIL_RECEIVE_ERROR, context);
  }
}

/**
 * Error class for email attachment errors
 */
export class EmailAttachmentError extends ValidationError {
  /**
   * Creates a new email attachment error
   * 
   * @param message Error message
   * @param context Additional context
   */
  constructor(
    message: string,
    context: IErrorContext = {}
  ) {
    super(message, EMAIL_ATTACHMENT_ERROR, context);
  }

  /**
   * Creates an instance for an attachment too large error
   * 
   * @param size Attachment size in bytes
   * @param maxSize Maximum allowed size in bytes
   * @param filename Attachment filename
   * @param context Additional context
   */
  public static tooLarge(
    size: number,
    maxSize: number,
    filename?: string,
    context: IErrorContext = {}
  ): EmailAttachmentError {
    const filenameText = filename ? ` (${filename})` : '';
    return new EmailAttachmentError(
      `Attachment${filenameText} size ${size} bytes exceeds maximum allowed size of ${maxSize} bytes`,
      {
        ...context,
        data: {
          ...context.data,
          size,
          maxSize,
          filename
        },
        userMessage: `The attachment${filenameText} is too large. Maximum size is ${Math.round(maxSize / 1024 / 1024)} MB.`
      }
    );
  }

  /**
   * Creates an instance for an invalid attachment type error
   * 
   * @param contentType Attachment content type
   * @param filename Attachment filename
   * @param allowedTypes List of allowed content types
   * @param context Additional context
   */
  public static invalidType(
    contentType: string,
    filename: string,
    allowedTypes: string[],
    context: IErrorContext = {}
  ): EmailAttachmentError {
    return new EmailAttachmentError(
      `Attachment '${filename}' with content type '${contentType}' is not allowed. Allowed types: ${allowedTypes.join(', ')}`,
      {
        ...context,
        data: {
          ...context.data,
          contentType,
          filename,
          allowedTypes
        },
        userMessage: `The attachment type ${contentType} is not allowed.`
      }
    );
  }
}

/**
 * Error class for email parsing errors
 */
export class EmailParseError extends OperationError {
  /**
   * Creates a new email parse error
   * 
   * @param message Error message
   * @param context Additional context
   */
  constructor(
    message: string,
    context: IErrorContext = {}
  ) {
    super(message, EMAIL_PARSE_ERROR, context);
  }
}

/**
 * Error class for email rate limit exceeded errors
 */
export class EmailRateLimitError extends ResourceError {
  /**
   * Creates a new email rate limit error
   * 
   * @param message Error message
   * @param context Additional context
   */
  constructor(
    message: string,
    context: IErrorContext = {}
  ) {
    super(message, EMAIL_RATE_LIMIT_EXCEEDED, context);
  }

  /**
   * Creates an instance with rate limit information
   * 
   * @param limit Rate limit
   * @param remaining Remaining quota
   * @param resetAt Time when the quota resets
   * @param scope Rate limit scope (global, domain, user, etc.)
   * @param context Additional context
   */
  public static withLimitInfo(
    limit: number,
    remaining: number,
    resetAt: Date | number,
    scope: string = 'global',
    context: IErrorContext = {}
  ): EmailRateLimitError {
    const resetTime = typeof resetAt === 'number' ? new Date(resetAt) : resetAt;
    const resetTimeStr = resetTime.toISOString();
    
    return new EmailRateLimitError(
      `Email rate limit exceeded: ${remaining}/${limit} remaining in ${scope} scope, resets at ${resetTimeStr}`,
      {
        ...context,
        data: {
          ...context.data,
          limit,
          remaining,
          resetAt: resetTime.getTime(),
          resetTimeStr,
          scope
        },
        userMessage: `You've reached the email sending limit. Please try again later.`
      }
    );
  }
}