// CBDC Transaction Modes - Online, Offline, Dual-Mode

import prisma from '@/shared/database/prisma';
import { Decimal } from '@prisma/client/runtime/library';
import { CbdcOfflineCapsule } from '@/shared/types';
import { encryptionService } from '@/infrastructure/encryption/encryption.service';
import { DEFAULT_CONFIG } from '@/shared/constants';
import { v4 as uuidv4 } from 'uuid';


export class CbdcTransactionService {
  /**
   * Create offline transaction capsule
   */
  async createOfflineCapsule(
    senderWalletId: string,
    receiverWalletId: string,
    amount: string
  ): Promise<CbdcOfflineCapsule> {
    const capsuleId = `CAPSULE-${uuidv4()}`;
    const doubleSpendToken = encryptionService.generateNonce();
    const timestamp = new Date();

    // Create signature payload
    const payload = JSON.stringify({
      capsuleId,
      senderWalletId,
      receiverWalletId,
      amount,
      timestamp: timestamp.toISOString(),
      doubleSpendToken,
    });

    const signature = encryptionService.hash(payload);

    const capsule = await prisma.cbdc_offline_capsules.create({
      data: {
        id: uuidv4(),
        capsuleId,
        senderWalletId,
        receiverWalletId,
        amount: new Decimal(amount),
        timestamp,
        expiryWindow: DEFAULT_CONFIG.OFFLINE_CAPSULE_EXPIRY_SECONDS,
        doubleSpendToken,
        signature,
        status: 'pending',
      },
    });

    return {
      capsuleId: capsule.capsuleId,
      senderWalletId: capsule.senderWalletId,
      receiverWalletId: capsule.receiverWalletId,
      amount: capsule.amount.toString(),
      timestamp: capsule.timestamp,
      expiryWindow: capsule.expiryWindow,
      doubleSpendToken: capsule.doubleSpendToken,
      signature: capsule.signature,
    };
  }

  /**
   * Validate and sync offline capsule
   */
  async validateAndSyncCapsule(capsuleId: string): Promise<boolean> {
    const capsule = await prisma.cbdc_offline_capsules.findUnique({
      where: { capsuleId },
    });

    if (!capsule) {
      return false;
    }

    // Check expiry
    const now = new Date();
    const expiryTime = new Date(capsule.timestamp.getTime() + capsule.expiryWindow * 1000);
    if (now > expiryTime) {
      await prisma.cbdc_offline_capsules.update({
        where: { capsuleId },
        data: { status: 'rejected' },
      });
      return false;
    }

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

    if (existingCapsule && existingCapsule.capsuleId !== capsuleId) {
      await prisma.cbdc_offline_capsules.update({
        where: { capsuleId },
        data: { status: 'rejected' },
      });
      return false;
    }

    // Validate signature
    const payload = JSON.stringify({
      capsuleId: capsule.capsuleId,
      senderWalletId: capsule.senderWalletId,
      receiverWalletId: capsule.receiverWalletId,
      amount: capsule.amount.toString(),
      timestamp: capsule.timestamp.toISOString(),
      doubleSpendToken: capsule.doubleSpendToken,
    });

    const computedSignature = encryptionService.hash(payload);
    if (computedSignature !== capsule.signature) {
      return false;
    }

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

    return true;
  }
}

export const cbdcTransactionService = new CbdcTransactionService();

