import * as plugins from '../../plugins.js';
import { logger } from '../../logger.js';
import { SecurityLogger, SecurityLogLevel, SecurityEventType } from '../../security/index.js';
import { RustSecurityBridge } from '../../security/classes.rustsecuritybridge.js';
import type { Email } from '../core/classes.email.js';

/**
 * SPF result qualifiers
 */
export enum SpfQualifier {
  PASS = '+',
  NEUTRAL = '?',
  SOFTFAIL = '~',
  FAIL = '-'
}

/**
 * SPF mechanism types
 */
export enum SpfMechanismType {
  ALL = 'all',
  INCLUDE = 'include',
  A = 'a',
  MX = 'mx',
  IP4 = 'ip4',
  IP6 = 'ip6',
  EXISTS = 'exists',
  REDIRECT = 'redirect',
  EXP = 'exp'
}

/**
 * SPF mechanism definition
 */
export interface SpfMechanism {
  qualifier: SpfQualifier;
  type: SpfMechanismType;
  value?: string;
}

/**
 * SPF record parsed data
 */
export interface SpfRecord {
  version: string;
  mechanisms: SpfMechanism[];
  modifiers: Record<string, string>;
}

/**
 * SPF verification result
 */
export interface SpfResult {
  result: 'pass' | 'neutral' | 'softfail' | 'fail' | 'temperror' | 'permerror' | 'none';
  explanation?: string;
  domain: string;
  ip: string;
  record?: string;
  error?: string;
}

/**
 * Class for verifying SPF records.
 * Delegates actual SPF evaluation to the Rust security bridge.
 * Retains parseSpfRecord() for lightweight local parsing.
 */
export class SpfVerifier {
  constructor(_dnsManager?: any) {
    // dnsManager is no longer needed — Rust handles DNS lookups
  }

  /**
   * Parse SPF record from TXT record (pure string parsing, no DNS)
   */
  public parseSpfRecord(record: string): SpfRecord | null {
    if (!record.startsWith('v=spf1')) {
      return null;
    }

    try {
      const spfRecord: SpfRecord = {
        version: 'spf1',
        mechanisms: [],
        modifiers: {}
      };

      const terms = record.split(' ').filter(term => term.length > 0);

      for (let i = 1; i < terms.length; i++) {
        const term = terms[i];

        if (term.includes('=')) {
          const [name, value] = term.split('=');
          spfRecord.modifiers[name] = value;
          continue;
        }

        let qualifier = SpfQualifier.PASS;
        let mechanismText = term;

        if (term.startsWith('+') || term.startsWith('-') ||
            term.startsWith('~') || term.startsWith('?')) {
          qualifier = term[0] as SpfQualifier;
          mechanismText = term.substring(1);
        }

        const colonIndex = mechanismText.indexOf(':');
        let type: SpfMechanismType;
        let value: string | undefined;

        if (colonIndex !== -1) {
          type = mechanismText.substring(0, colonIndex) as SpfMechanismType;
          value = mechanismText.substring(colonIndex + 1);
        } else {
          type = mechanismText as SpfMechanismType;
        }

        spfRecord.mechanisms.push({ qualifier, type, value });
      }

      return spfRecord;
    } catch (error) {
      logger.log('error', `Error parsing SPF record: ${error.message}`, {
        record,
        error: error.message
      });
      return null;
    }
  }

  /**
   * Verify SPF for a given email — delegates to Rust bridge
   */
  public async verify(
    email: Email,
    ip: string,
    heloDomain: string
  ): Promise<SpfResult> {
    const securityLogger = SecurityLogger.getInstance();
    const mailFrom = email.from || '';
    const domain = mailFrom.split('@')[1] || '';

    try {
      const bridge = RustSecurityBridge.getInstance();
      const result = await bridge.checkSpf({
        ip,
        heloDomain,
        hostname: plugins.os.hostname(),
        mailFrom,
      });

      const spfResult: SpfResult = {
        result: result.result as SpfResult['result'],
        domain: result.domain,
        ip: result.ip,
        explanation: result.explanation ?? undefined,
      };

      securityLogger.logEvent({
        level: spfResult.result === 'pass' ? SecurityLogLevel.INFO :
               (spfResult.result === 'fail' ? SecurityLogLevel.WARN : SecurityLogLevel.INFO),
        type: SecurityEventType.SPF,
        message: `SPF ${spfResult.result} for ${spfResult.domain} from IP ${ip}`,
        domain: spfResult.domain,
        details: { ip, heloDomain, result: spfResult.result, explanation: spfResult.explanation },
        success: spfResult.result === 'pass'
      });

      return spfResult;
    } catch (error) {
      logger.log('error', `SPF verification error: ${error.message}`, { domain, ip, error: error.message });

      securityLogger.logEvent({
        level: SecurityLogLevel.ERROR,
        type: SecurityEventType.SPF,
        message: `SPF verification error for ${domain}`,
        domain,
        details: { ip, error: error.message },
        success: false
      });

      return {
        result: 'temperror',
        explanation: `Error verifying SPF: ${error.message}`,
        domain,
        ip,
        error: error.message
      };
    }
  }

  /**
   * Check if email passes SPF verification and apply headers
   */
  public async verifyAndApply(
    email: Email,
    ip: string,
    heloDomain: string
  ): Promise<boolean> {
    const result = await this.verify(email, ip, heloDomain);

    email.headers['Received-SPF'] = `${result.result} (${result.domain}: ${result.explanation || ''}) client-ip=${ip}; envelope-from=${email.getEnvelopeFrom()}; helo=${heloDomain};`;

    switch (result.result) {
      case 'fail':
        email.mightBeSpam = true;
        logger.log('warn', `SPF failed for ${result.domain} from ${ip}: ${result.explanation}`);
        return false;

      case 'softfail':
        email.mightBeSpam = true;
        logger.log('info', `SPF softfailed for ${result.domain} from ${ip}: ${result.explanation}`);
        return true;

      case 'neutral':
      case 'none':
        logger.log('info', `SPF ${result.result} for ${result.domain} from ${ip}: ${result.explanation}`);
        return true;

      case 'pass':
        logger.log('info', `SPF passed for ${result.domain} from ${ip}: ${result.explanation}`);
        return true;

      case 'temperror':
      case 'permerror':
        logger.log('error', `SPF error for ${result.domain} from ${ip}: ${result.explanation}`);
        return true;

      default:
        return true;
    }
  }
}
