// Quantum Capsule Service
// Offline capsule management with double-spend prevention

import prisma from '@/shared/database/prisma';
import { Decimal } from '@prisma/client/runtime/library';
import { v4 as uuidv4 } from 'uuid';
import { createHash } from 'crypto';
import { quantumCryptoService } from '@/infrastructure/quantum/quantum-crypto.service';


export interface CapsuleCreationRequest {
  senderWalletId: string;
  receiverWalletId: string;
  amount: string;
  expiryWindow: number; // seconds
}

export interface CapsuleResult {
  capsuleId: string;
  doubleSpendToken: string;
  pqcSignature: string;
  status: string;
}

export class QuantumCapsuleService {
  /**
   * Create offline quantum capsule
   */
  async createCapsule(
    request: CapsuleCreationRequest
  ): Promise<CapsuleResult> {
    const senderWallet = await prisma.quantumWallet.findUnique({
      where: { walletId: request.senderWalletId },
    });

    if (!senderWallet) {
      throw new Error(`Sender wallet not found: ${request.senderWalletId}`);
    }

    // Check balance
    if (senderWallet.balance.lessThan(new Decimal(request.amount))) {
      throw new Error('Insufficient balance');
    }

    // Generate double-spend token
    const doubleSpendToken = this.generateDoubleSpendToken(
      request.senderWalletId,
      request.receiverWalletId,
      request.amount
    );

    // Create capsule payload
    const capsulePayload = {
      senderWalletId: request.senderWalletId,
      receiverWalletId: request.receiverWalletId,
      amount: request.amount,
      timestamp: new Date().toISOString(),
      doubleSpendToken,
      expiryWindow: request.expiryWindow,
    };

    const payloadString = JSON.stringify(capsulePayload);

    // Sign with PQC (Dilithium)
    const pqcSignature = await this.signWithPQC(
      payloadString,
      senderWallet.dilithiumKeyId
    );

    // Create capsule
    const capsuleId = `CAPSULE-${uuidv4()}`;
    const capsule = await prisma.quantumWalletCapsule.create({
      data: {
        capsuleId,
        senderWalletId: request.senderWalletId,
        receiverWalletId: request.receiverWalletId,
        amount: new Decimal(request.amount),
        timestamp: new Date(),
        expiryWindow: request.expiryWindow,
        doubleSpendToken,
        pqcSignature,
        status: 'pending',
      },
    });

    // Reserve balance
    await prisma.quantumWallet.update({
      where: { walletId: request.senderWalletId },
      data: {
        balance: senderWallet.balance.minus(new Decimal(request.amount)),
      },
    });

    return {
      capsuleId: capsule.capsuleId,
      doubleSpendToken: capsule.doubleSpendToken,
      pqcSignature: capsule.pqcSignature,
      status: capsule.status,
    };
  }

  /**
   * Validate capsule (dual verification: SCB + DBIS)
   */
  async validateCapsule(capsuleId: string): Promise<{
    valid: boolean;
    scbVerified: boolean;
    dbisVerified: boolean;
  }> {
    const capsule = await prisma.quantumWalletCapsule.findUnique({
      where: { capsuleId },
      include: { wallet: true },
    });

    if (!capsule) {
      return { valid: false, scbVerified: false, dbisVerified: false };
    }

    // Check double-spend token
    const existingCapsule = await prisma.quantumWalletCapsule.findFirst({
      where: {
        doubleSpendToken: capsule.doubleSpendToken,
        NOT: { capsuleId: capsule.capsuleId },
        status: { in: ['validated', 'synced'] },
      },
    });

    if (existingCapsule) {
      return { valid: false, scbVerified: false, dbisVerified: false };
    }

    // Verify PQC signature (SCB verification)
    const capsulePayload = {
      senderWalletId: capsule.senderWalletId,
      receiverWalletId: capsule.receiverWalletId,
      amount: capsule.amount.toString(),
      timestamp: capsule.timestamp.toISOString(),
      doubleSpendToken: capsule.doubleSpendToken,
      expiryWindow: capsule.expiryWindow,
    };

    const payloadString = JSON.stringify(capsulePayload);
    const scbVerified = await this.verifyPQCSignature(
      payloadString,
      capsule.pqcSignature,
      capsule.wallet.dilithiumKeyId
    );

    // DBIS verification (simplified - in production would have separate DBIS verification)
    const dbisVerified = scbVerified; // For now, use same verification

    const valid = scbVerified && dbisVerified;

    if (valid) {
      await prisma.quantumWalletCapsule.update({
        where: { capsuleId },
        data: {
          scbVerification: true,
          dbisVerification: true,
          status: 'validated',
        },
      });
    }

    return {
      valid,
      scbVerified,
      dbisVerified,
    };
  }

  /**
   * Sync capsule (finalize offline transaction)
   */
  async syncCapsule(capsuleId: string): Promise<void> {
    const capsule = await prisma.quantumWalletCapsule.findUnique({
      where: { capsuleId },
      include: { wallet: true },
    });

    if (!capsule) {
      throw new Error(`Capsule not found: ${capsuleId}`);
    }

    if (capsule.status !== 'validated') {
      throw new Error(`Capsule must be validated before sync: ${capsule.status}`);
    }

    // Update receiver wallet balance
    const receiverWallet = await prisma.quantumWallet.findUnique({
      where: { walletId: capsule.receiverWalletId },
    });

    if (!receiverWallet) {
      throw new Error(`Receiver wallet not found: ${capsule.receiverWalletId}`);
    }

    await prisma.quantumWallet.update({
      where: { walletId: capsule.receiverWalletId },
      data: {
        balance: receiverWallet.balance.plus(capsule.amount),
      },
    });

    // Mark capsule as synced
    await prisma.quantumWalletCapsule.update({
      where: { capsuleId },
      data: {
        status: 'synced',
        syncedAt: new Date(),
      },
    });
  }

  /**
   * Generate double-spend token
   */
  private generateDoubleSpendToken(
    senderWalletId: string,
    receiverWalletId: string,
    amount: string
  ): string {
    const data = `${senderWalletId}:${receiverWalletId}:${amount}:${Date.now()}`;
    return createHash('sha3-256').update(data).digest('hex');
  }

  /**
   * Sign with PQC
   */
  private async signWithPQC(message: string, dilithiumKeyId: string): Promise<string> {
    // Get key
    const key = await prisma.cryptographicKey.findUnique({
      where: { keyId: dilithiumKeyId },
    });

    if (!key) {
      throw new Error(`Key not found: ${dilithiumKeyId}`);
    }

    // In production, would use actual PQC library
    // For now, generate signature hash
    const signature = createHash('sha3-256')
      .update(message + key.publicKey)
      .digest('hex');

    return `PQC-SIG-${signature}`;
  }

  /**
   * Verify PQC signature
   */
  private async verifyPQCSignature(
    message: string,
    signature: string,
    dilithiumKeyId: string
  ): Promise<boolean> {
    // Get key
    const key = await prisma.cryptographicKey.findUnique({
      where: { keyId: dilithiumKeyId },
    });

    if (!key) {
      return false;
    }

    // In production, would use actual PQC library
    // For now, verify signature format
    const expectedSignature = createHash('sha3-256')
      .update(message + key.publicKey)
      .digest('hex');

    return signature === `PQC-SIG-${expectedSignature}`;
  }
}

export const quantumCapsuleService = new QuantumCapsuleService();

