// AS4 Certificate Manager Service
// Handles certificate validation, pinning, and lifecycle management

import { createHash } from 'crypto';
import { memberDirectoryService } from './member-directory.service';
import { DbisError, ErrorCode } from '@/shared/types';
import { logger } from '@/infrastructure/monitoring/logger';

export interface CertificateInfo {
  fingerprint: string;
  certificateType: 'TLS' | 'SIGNING' | 'ENCRYPTION';
  validFrom: Date;
  validTo: Date;
  status: 'active' | 'expired' | 'revoked';
}

export class CertificateManagerService {
  /**
   * Calculate SHA-256 fingerprint of certificate
   */
  calculateFingerprint(certificatePem: string): string {
    // Remove PEM headers/footers and whitespace
    const certData = certificatePem
      .replace(/-----BEGIN CERTIFICATE-----/g, '')
      .replace(/-----END CERTIFICATE-----/g, '')
      .replace(/\s/g, '');

    const certBuffer = Buffer.from(certData, 'base64');
    const hash = createHash('sha256').update(certBuffer).digest('hex');
    return hash.toUpperCase();
  }

  /**
   * Validate certificate fingerprint against member directory
   */
  async validateCertificateFingerprint(
    memberId: string,
    fingerprint: string,
    certificateType: 'TLS' | 'SIGNING' | 'ENCRYPTION'
  ): Promise<boolean> {
    const member = await memberDirectoryService.getMember(memberId);

    if (!member) {
      return false;
    }

    // For TLS, check main fingerprint
    if (certificateType === 'TLS') {
      return member.tlsCertFingerprint.toUpperCase() === fingerprint.toUpperCase();
    }

    // For signing/encryption, check respective fingerprints
    if (certificateType === 'SIGNING') {
      return member.signingCertFingerprint?.toUpperCase() === fingerprint.toUpperCase();
    }

    if (certificateType === 'ENCRYPTION') {
      return member.encryptionCertFingerprint?.toUpperCase() === fingerprint.toUpperCase();
    }

    return false;
  }

  /**
   * Validate certificate chain
   */
  async validateCertificateChain(
    certificatePem: string,
    chainPem?: string[]
  ): Promise<{ valid: boolean; error?: string }> {
    try {
      // TODO: Implement actual certificate chain validation
      // This would use a library like node-forge or @peculiar/x509
      // For now, return basic validation

      if (!certificatePem || certificatePem.trim().length === 0) {
        return { valid: false, error: 'Certificate is empty' };
      }

      // Basic PEM format validation
      if (
        !certificatePem.includes('-----BEGIN CERTIFICATE-----') ||
        !certificatePem.includes('-----END CERTIFICATE-----')
      ) {
        return { valid: false, error: 'Invalid PEM format' };
      }

      return { valid: true };
    } catch (error) {
      logger.error('Certificate chain validation failed', {
        error: error instanceof Error ? error.message : 'Unknown error',
      });
      return { valid: false, error: 'Certificate validation error' };
    }
  }

  /**
   * Check if certificate is expired
   */
  isCertificateExpired(validTo: Date): boolean {
    return new Date() > validTo;
  }

  /**
   * Check if certificate is about to expire (within 30 days)
   */
  isCertificateExpiringSoon(validTo: Date, daysThreshold: number = 30): boolean {
    const thresholdDate = new Date();
    thresholdDate.setDate(thresholdDate.getDate() + daysThreshold);
    return validTo <= thresholdDate;
  }

  /**
   * Validate certificate for member
   */
  async validateMemberCertificate(
    memberId: string,
    certificatePem: string,
    certificateType: 'TLS' | 'SIGNING' | 'ENCRYPTION'
  ): Promise<{ valid: boolean; error?: string }> {
    // Calculate fingerprint
    const fingerprint = this.calculateFingerprint(certificatePem);

    // Validate fingerprint against directory
    const fingerprintValid = await this.validateCertificateFingerprint(
      memberId,
      fingerprint,
      certificateType
    );

    if (!fingerprintValid) {
      return {
        valid: false,
        error: `Certificate fingerprint does not match registered fingerprint for member ${memberId}`,
      };
    }

    // Validate certificate chain
    const chainValidation = await this.validateCertificateChain(certificatePem);

    if (!chainValidation.valid) {
      return chainValidation;
    }

    // Check expiration (would need to parse certificate)
    // For now, assume valid if fingerprint matches

    return { valid: true };
  }

  /**
   * Get certificate expiration warnings
   */
  async getExpirationWarnings(daysThreshold: number = 30): Promise<
    Array<{
      memberId: string;
      certificateType: string;
      expiresAt: Date;
      daysUntilExpiration: number;
    }>
  > {
    const warnings: Array<{
      memberId: string;
      certificateType: string;
      expiresAt: Date;
      daysUntilExpiration: number;
    }> = [];

    // Get all active members
    const members = await memberDirectoryService.searchMembers({ status: 'active' });

    for (const member of members) {
      const certificates = await memberDirectoryService.getMemberCertificates(member.memberId);

      for (const cert of certificates) {
        if (cert.status === 'active' && this.isCertificateExpiringSoon(cert.validTo, daysThreshold)) {
          const daysUntilExpiration = Math.ceil(
            (cert.validTo.getTime() - new Date().getTime()) / (1000 * 60 * 60 * 24)
          );

          warnings.push({
            memberId: member.memberId,
            certificateType: cert.certificateType,
            expiresAt: cert.validTo,
            daysUntilExpiration,
          });
        }
      }
    }

    return warnings;
  }
}

export const certificateManagerService = new CertificateManagerService();
