import { DPoPService } from './DPoPService';
import { CryptoService } from './CryptoService';
import { KeyManagementService } from './KeyManagementService';
import type { SecurityConfig, EncryptionResult, KeyReference } from './types';

/**
 * Core Security SDK
 * Provides hardware-backed cryptography, DPoP implementation, and contextual encryption
 * 
 * Key Features (per FRD):
 * - F.SC.001: Cryptographic utilities (AES-GCM envelope encryption)
 * - F.SC.002: Hardware-backed key storage (Keychain/StrongBox)
 * - F.SC.003: Certificate Pinning logic
 * - F.SC.004: DPoP proof generation
 * - F.SC.005: Organizational Data Encryption Keys (DEKs) management
 * - F.SC.006: Secure wipe/cryptographic erasure
 * - F.SC.007: Device attestation integration
 */
export class SecurityCore {
  private config: SecurityConfig;
  private dpopService: DPoPService;
  private cryptoService: CryptoService;
  private keyManagement: KeyManagementService;
  private initialized = false;

  constructor(config: SecurityConfig) {
    this.config = config;
    this.dpopService = new DPoPService();
    this.cryptoService = new CryptoService();
    this.keyManagement = new KeyManagementService(config);
  }

  /**
   * Initialize the Security Core
   * Must be called before any other operations
   */
  async initialize(): Promise<void> {
    if (this.initialized) return;

    await this.keyManagement.initialize();
    await this.dpopService.initializeKeyPair();
    
    this.initialized = true;
  }

  /**
   * F.SC.004: Generate DPoP proof for request authentication
   */
  async signDPoPProof(method: string, uri: string, accessToken?: string): Promise<string> {
    this.ensureInitialized();
    return this.dpopService.signProof(method, uri, accessToken);
  }

  /**
   * F.SC.001: Encrypt data using organizational DEK (envelope encryption)
   */
  async encryptForOrganization(data: string, orgId: string): Promise<EncryptionResult> {
    this.ensureInitialized();
    
    // Get or create organizational DEK
    const orgKeyRef = await this.keyManagement.getOrganizationalKey(orgId);
    
    // Generate random file encryption key
    const fileKey = await this.cryptoService.generateKey();
    
    // Encrypt data with file key
    const encryptedData = await this.cryptoService.encrypt(data, fileKey);
    
    // Wrap file key with organizational DEK
    const wrappedKey = await this.cryptoService.wrapKey(fileKey, orgKeyRef.keyId);
    
    return {
      encryptedData: encryptedData.ciphertext,
      keyReference: {
        keyId: wrappedKey,
        orgId,
        keyType: 'dek',
        createdAt: new Date().toISOString()
      },
      iv: encryptedData.iv,
      authTag: encryptedData.authTag
    };
  }

  /**
   * Decrypt data using organizational DEK
   */
  async decryptForOrganization(encryptedData: string, keyReference: KeyReference): Promise<string> {
    this.ensureInitialized();
    
    if (!keyReference.orgId) {
      throw new Error('Organization ID required for decryption');
    }

    // Get organizational DEK
    const orgKeyRef = await this.keyManagement.getOrganizationalKey(keyReference.orgId);
    
    // Unwrap file key
    const fileKey = await this.cryptoService.unwrapKey(keyReference.keyId, orgKeyRef.keyId);
    
    // Decrypt data
    return this.cryptoService.decrypt(encryptedData, fileKey);
  }

  /**
   * F.SC.002: Get database master key from secure storage
   */
  async getDatabaseMasterKey(): Promise<string> {
    this.ensureInitialized();
    return this.keyManagement.getDatabaseMasterKey();
  }

  /**
   * F.SC.005: Store authentication tokens securely
   */
  async storeAuthTokens(accessToken: string, refreshToken: string): Promise<void> {
    this.ensureInitialized();
    await this.keyManagement.storeSecureValue('auth.access_token', accessToken);
    await this.keyManagement.storeSecureValue('auth.refresh_token', refreshToken);
  }

  /**
   * Get stored authentication tokens
   */
  async getAuthTokens(): Promise<{ accessToken?: string; refreshToken?: string }> {
    this.ensureInitialized();
    
    const [accessToken, refreshToken] = await Promise.all([
      this.keyManagement.getSecureValue('auth.access_token'),
      this.keyManagement.getSecureValue('auth.refresh_token')
    ]);

    return { accessToken, refreshToken };
  }

  /**
   * F.SC.006: Cryptographic erasure - delete organizational keys
   */
  async performCryptographicErasure(orgId: string): Promise<void> {
    this.ensureInitialized();
    await this.keyManagement.deleteOrganizationalKeys(orgId);
  }

  /**
   * F.SC.006: Complete secure wipe - delete all keys
   */
  async performSecureWipe(): Promise<void> {
    this.ensureInitialized();
    await this.keyManagement.secureWipe();
  }

  /**
   * Sign arbitrary data with identity key
   */
  async signData(data: string): Promise<string> {
    this.ensureInitialized();
    return this.dpopService.signData(data);
  }

  private ensureInitialized(): void {
    if (!this.initialized) {
      throw new Error('SecurityCore must be initialized before use');
    }
  }
}