// Encryption Service - AES-256, TLS 1.3, Hash Functions

import crypto from 'crypto';
import { DEFAULT_CONFIG } from '@/shared/constants';

export class EncryptionService {
  private readonly algorithm = 'aes-256-gcm';
  private readonly keyLength = 32; // 256 bits
  private readonly ivLength = 16; // 128 bits
  private readonly tagLength = 16; // 128 bits

  /**
   * Generate a random encryption key
   */
  generateKey(): Buffer {
    return crypto.randomBytes(this.keyLength);
  }

  /**
   * Generate a random IV (Initialization Vector)
   */
  generateIV(): Buffer {
    return crypto.randomBytes(this.ivLength);
  }

  /**
   * Encrypt data using AES-256-GCM
   */
  encrypt(data: string, key: Buffer): { encrypted: string; iv: string; tag: string } {
    const iv = this.generateIV();
    const cipher = crypto.createCipheriv(this.algorithm, key, iv);

    let encrypted = cipher.update(data, 'utf8', 'hex');
    encrypted += cipher.final('hex');

    const tag = cipher.getAuthTag();

    return {
      encrypted,
      iv: iv.toString('hex'),
      tag: tag.toString('hex'),
    };
  }

  /**
   * Decrypt data using AES-256-GCM
   */
  decrypt(encrypted: string, key: Buffer, iv: string, tag: string): string {
    const ivBuffer = Buffer.from(iv, 'hex');
    const tagBuffer = Buffer.from(tag, 'hex');
    const decipher = crypto.createDecipheriv(this.algorithm, key, ivBuffer);

    decipher.setAuthTag(tagBuffer);

    let decrypted = decipher.update(encrypted, 'hex', 'utf8');
    decrypted += decipher.final('utf8');

    return decrypted;
  }

  /**
   * Hash data using SHA-3 (Keccak-256)
   */
  hash(data: string): string {
    return crypto.createHash('sha3-256').update(data).digest('hex');
  }

  /**
   * Hash data for ledger block chaining
   */
  hashLedgerEntry(entry: {
    id: string;
    debitAccountId: string;
    creditAccountId: string;
    amount: string;
    currencyCode: string;
    timestampUtc: Date;
    previousHash?: string;
  }): string {
    const data = JSON.stringify({
      id: entry.id,
      debitAccountId: entry.debitAccountId,
      creditAccountId: entry.creditAccountId,
      amount: entry.amount,
      currencyCode: entry.currencyCode,
      timestampUtc: entry.timestampUtc.toISOString(),
      previousHash: entry.previousHash || '',
    });

    return this.hash(data);
  }

  /**
   * Create a hash chain for multiple ledger entries
   */
  createHashChain(entries: Array<{ id: string; data: string }>): string[] {
    const hashes: string[] = [];
    let previousHash: string | undefined;

    for (const entry of entries) {
      const entryData = {
        ...entry,
        previousHash: previousHash || '',
      };
      const hash = this.hash(JSON.stringify(entryData));
      hashes.push(hash);
      previousHash = hash;
    }

    return hashes;
  }

  /**
   * Verify hash chain integrity
   */
  verifyHashChain(entries: Array<{ id: string; data: string; hash: string }>): boolean {
    let previousHash: string | undefined;

    for (const entry of entries) {
      const entryData = {
        id: entry.id,
        data: entry.data,
        previousHash: previousHash || '',
      };
      const computedHash = this.hash(JSON.stringify(entryData));

      if (computedHash !== entry.hash) {
        return false;
      }

      previousHash = entry.hash;
    }

    return true;
  }

  /**
   * Generate a secure random nonce
   */
  generateNonce(): string {
    return crypto.randomBytes(16).toString('hex');
  }

  /**
   * Create HMAC signature
   */
  createHMAC(data: string, secret: string): string {
    return crypto.createHmac('sha256', secret).update(data).digest('hex');
  }

  /**
   * Verify HMAC signature
   */
  verifyHMAC(data: string, secret: string, signature: string): boolean {
    const computedSignature = this.createHMAC(data, secret);
    return crypto.timingSafeEqual(
      Buffer.from(computedSignature),
      Buffer.from(signature)
    );
  }
}

export const encryptionService = new EncryptionService();

