/**
 * Crypto Module
 * @countermeasure/web-components
 *
 * Client-side encryption utilities compatible with FluxEncrypt.
 * Provides AES-256-GCM symmetric encryption and RSA-OAEP hybrid encryption.
 */

// ============================================================================
// TYPES
// ============================================================================

export type {
  EncodingFormat,
  SymmetricCipherConfig,
  EncryptedData,
  SymmetricCipher,
  HybridCipherConfig,
  KeyPair,
  ExportedKeyPair,
  HybridCipher,
  KeyDerivationConfig,
  DerivedKeyResult,
  CryptoManagerConfig,
  CryptoManager,
  CryptoErrorCode,
} from './types'

export { CryptoError } from './types'

// ============================================================================
// ENCODING
// ============================================================================

export {
  toBase64,
  fromBase64,
  toHex,
  fromHex,
  stringToBytes,
  bytesToString,
  encodeEncryptedData,
  decodeEncryptedData,
  constantTimeEqual,
  zeroize,
  concat,
} from './encoding'

export { encodeOutput, decodeInput } from './encoding-helpers'

// ============================================================================
// KEYS
// ============================================================================

export {
  generateSymmetricKey,
  importSymmetricKey,
  generateIV,
  randomBytes,
  generateKeyPair,
  exportPublicKey,
  exportPrivateKey,
  importPublicKey,
  importPrivateKey,
  deriveKeyFromPassword,
  exportDerivedKey,
} from './keys'

// ============================================================================
// SYMMETRIC ENCRYPTION
// ============================================================================

export {
  SymmetricCipherImpl,
  createSymmetricCipher,
  createSymmetricCipherFromKey,
  encryptSecret,
  decryptSecret,
} from './symmetric'

// ============================================================================
// HYBRID ENCRYPTION
// ============================================================================

export {
  HybridCipherImpl,
  createHybridCipher,
  hybridEncrypt,
  hybridDecrypt,
  hybridDecryptToString,
} from './hybrid'

// ============================================================================
// UNIFIED CRYPTO MANAGER
// ============================================================================

import { createHybridCipher } from './hybrid'
import {
  generateSymmetricKey,
  generateKeyPair,
  exportPublicKey,
  exportPrivateKey,
  importPublicKey,
  importPrivateKey,
  deriveKeyFromPassword,
} from './keys'
import { createSymmetricCipher } from './symmetric'

import type { CryptoManagerConfig, KeyPair, DerivedKeyResult } from './types'

/**
 * Unified crypto manager providing access to all encryption operations.
 * Mirrors FluxEncrypt's Cryptum interface.
 *
 * Usage:
 * ```typescript
 * const crypto = createCryptoManager()
 *
 * // Symmetric encryption
 * const key = await crypto.generateSymmetricKey()
 * const encrypted = await crypto.encryptSecret(key, 'my-secret')
 * const decrypted = await crypto.decryptSecret(key, encrypted)
 *
 * // Hybrid encryption
 * const keypair = await crypto.generateKeyPair()
 * const ciphertext = await crypto.encrypt(keypair.publicKey, 'secret data')
 * const plaintext = await crypto.decrypt(keypair.privateKey, ciphertext)
 * ```
 */
export class CryptoManagerImpl {
  private config: Required<CryptoManagerConfig>

  constructor(config: CryptoManagerConfig = {}) {
    this.config = {
      encoding: config.encoding ?? 'base64',
      rsaKeySize: config.rsaKeySize ?? 4096,
      pbkdf2Iterations: config.pbkdf2Iterations ?? 100000,
    }
  }

  // -------------------------------------------------------------------------
  // Symmetric Operations
  // -------------------------------------------------------------------------

  /**
   * Generate a new symmetric key (hex-encoded).
   */
  async generateSymmetricKey(): Promise<string> {
    return generateSymmetricKey()
  }

  /**
   * Encrypt a secret with a hex key.
   */
  async encryptSecret(hexKey: string, plaintext: string): Promise<string> {
    const cipher = await createSymmetricCipher(hexKey, { encoding: this.config.encoding })
    return cipher.encrypt(plaintext)
  }

  /**
   * Decrypt a secret with a hex key.
   */
  async decryptSecret(hexKey: string, ciphertext: string): Promise<string> {
    const cipher = await createSymmetricCipher(hexKey, { encoding: this.config.encoding })
    return cipher.decrypt(ciphertext)
  }

  // -------------------------------------------------------------------------
  // Hybrid Operations
  // -------------------------------------------------------------------------

  /**
   * Generate a new RSA key pair.
   */
  async generateKeyPair(): Promise<KeyPair> {
    return generateKeyPair(this.config.rsaKeySize)
  }

  /**
   * Encrypt data with a public key using hybrid encryption.
   */
  async encrypt(publicKey: CryptoKey, data: string | Uint8Array): Promise<string> {
    const cipher = createHybridCipher({
      encoding: this.config.encoding,
      rsaKeySize: this.config.rsaKeySize,
    })
    return cipher.encrypt(publicKey, data)
  }

  /**
   * Decrypt data with a private key using hybrid encryption.
   */
  async decrypt(privateKey: CryptoKey, ciphertext: string): Promise<Uint8Array> {
    const cipher = createHybridCipher({
      encoding: this.config.encoding,
      rsaKeySize: this.config.rsaKeySize,
    })
    return cipher.decrypt(privateKey, ciphertext)
  }

  /**
   * Decrypt data and return as string.
   */
  async decryptToString(privateKey: CryptoKey, ciphertext: string): Promise<string> {
    const cipher = createHybridCipher({
      encoding: this.config.encoding,
      rsaKeySize: this.config.rsaKeySize,
    })
    return cipher.decryptToString(privateKey, ciphertext)
  }

  // -------------------------------------------------------------------------
  // Key Management
  // -------------------------------------------------------------------------

  /**
   * Export a public key to PEM format.
   */
  async exportPublicKey(key: CryptoKey): Promise<string> {
    return exportPublicKey(key)
  }

  /**
   * Export a private key to PEM format.
   */
  async exportPrivateKey(key: CryptoKey): Promise<string> {
    return exportPrivateKey(key)
  }

  /**
   * Import a public key from PEM format.
   */
  async importPublicKey(pem: string): Promise<CryptoKey> {
    return importPublicKey(pem)
  }

  /**
   * Import a private key from PEM format.
   */
  async importPrivateKey(pem: string): Promise<CryptoKey> {
    return importPrivateKey(pem)
  }

  // -------------------------------------------------------------------------
  // Key Derivation
  // -------------------------------------------------------------------------

  /**
   * Derive a key from a password using PBKDF2.
   */
  async deriveKeyFromPassword(password: string, salt?: Uint8Array): Promise<DerivedKeyResult> {
    return deriveKeyFromPassword(password, salt, {
      iterations: this.config.pbkdf2Iterations,
    })
  }

  // -------------------------------------------------------------------------
  // Configuration
  // -------------------------------------------------------------------------

  /**
   * Get the current configuration.
   */
  getConfig(): Required<CryptoManagerConfig> {
    return { ...this.config }
  }
}

/**
 * Create a new CryptoManager instance.
 */
export function createCryptoManager(config: CryptoManagerConfig = {}): CryptoManagerImpl {
  return new CryptoManagerImpl(config)
}

// Default instance for simple usage
let defaultManager: CryptoManagerImpl | null = null

/**
 * Get the default CryptoManager instance.
 */
export function getDefaultCryptoManager(config?: CryptoManagerConfig): CryptoManagerImpl {
  defaultManager ??= createCryptoManager(config)
  return defaultManager
}

/**
 * Convenience function to create a CryptoManager (matches FluxEncrypt's `cryptum()` function).
 */
export function cryptum(config?: CryptoManagerConfig): CryptoManagerImpl {
  return createCryptoManager(config)
}
