// CIM Offline Service
// Cross-sovereign capsule recognition
// Double-spend protection registry
// Global capsule synchronization

import prisma from '@/shared/database/prisma';
import { Decimal } from '@prisma/client/runtime/library';
import { v4 as uuidv4 } from 'uuid';
import { createHash } from 'crypto';


export interface CimOfflineCapsuleRequest {
  sourceSovereignBankId: string;
  targetSovereignBankId: string;
  senderWalletId: string;
  receiverWalletId: string;
  amount: string;
  expiryWindow: number;
}

export interface CrossSovereignCapsuleResult {
  capsuleId: string;
  doubleSpendToken: string;
  signature: string;
  crossSovereignRecognition: boolean;
}

export class CimOfflineService {
  /**
   * Create cross-sovereign offline capsule
   */
  async createCrossSovereignCapsule(
    request: CimOfflineCapsuleRequest
  ): Promise<CrossSovereignCapsuleResult> {
    const capsuleId = `CIM-CAPSULE-${uuidv4()}`;
    const doubleSpendToken = this.generateDoubleSpendToken();
    const timestamp = new Date();

    // Create signature payload
    const payload = {
      capsuleId,
      sourceSovereignBankId: request.sourceSovereignBankId,
      targetSovereignBankId: request.targetSovereignBankId,
      senderWalletId: request.senderWalletId,
      receiverWalletId: request.receiverWalletId,
      amount: request.amount,
      timestamp: timestamp.toISOString(),
      doubleSpendToken,
      expiryWindow: request.expiryWindow,
    };

    const signature = this.generateCapsuleSignature(payload);

    // Create capsule
    const capsule = await prisma.cim_offline_capsules.create({
      data: {
        id: uuidv4(),
        capsuleId,
        updatedAt: new Date(),
        sourceSovereignBankId: request.sourceSovereignBankId,
        targetSovereignBankId: request.targetSovereignBankId,
        senderWalletId: request.senderWalletId,
        receiverWalletId: request.receiverWalletId,
        amount: new Decimal(request.amount),
        timestamp,
        expiryWindow: request.expiryWindow,
        doubleSpendToken,
        signature,
        crossSovereignRecognition: false, // Will be set during sync
        globalSyncStatus: 'pending',
        createdAt: new Date(),
      },
    });

    return {
      capsuleId: capsule.capsuleId,
      doubleSpendToken: capsule.doubleSpendToken,
      signature: capsule.signature,
      crossSovereignRecognition: false,
    };
  }

  /**
   * Generate double-spend token
   */
  private generateDoubleSpendToken(): string {
    return createHash('sha3-256')
      .update(uuidv4() + Date.now().toString())
      .digest('hex');
  }

  /**
   * Generate capsule signature
   */
  private generateCapsuleSignature(payload: Record<string, unknown>): string {
    const payloadString = JSON.stringify(payload);
    return createHash('sha3-256').update(payloadString).digest('hex');
  }

  /**
   * Recognize cross-sovereign capsule
   */
  async recognizeCrossSovereignCapsule(
    capsuleId: string,
    targetSovereignBankId: string
  ): Promise<boolean> {
    const capsule = await prisma.cim_offline_capsules.findUnique({
      where: { capsuleId },
    });

    if (!capsule) {
      return false;
    }

    // Verify capsule is for this target sovereign
    if (capsule.targetSovereignBankId !== targetSovereignBankId) {
      return false;
    }

    // Check double-spend protection
    const isDoubleSpend = await this.checkDoubleSpend(capsule.doubleSpendToken);

    if (isDoubleSpend) {
      await prisma.cim_offline_capsules.update({
        where: { capsuleId },
        data: {
          globalSyncStatus: 'rejected',
        },
      });
      return false;
    }

    // Recognize capsule
    await prisma.cim_offline_capsules.update({
      where: { capsuleId },
      data: {
        crossSovereignRecognition: true,
        globalSyncStatus: 'recognized',
      },
    });

    return true;
  }

  /**
   * Check double-spend protection
   */
  async checkDoubleSpend(doubleSpendToken: string): Promise<boolean> {
    // Check if token already exists in global registry
    const existingCapsule = await prisma.cim_offline_capsules.findFirst({
      where: {
        doubleSpendToken,
        globalSyncStatus: {
          in: ['recognized', 'synced'],
        },
      },
    });

    // Also check in regular offline capsules
    const regularCapsule = await prisma.cbdc_offline_capsules.findFirst({
      where: {
        doubleSpendToken,
        status: {
          in: ['validated', 'synced'],
        },
      },
    });

    return !!(existingCapsule || regularCapsule);
  }

  /**
   * Sync capsule globally
   */
  async syncCapsuleGlobally(capsuleId: string): Promise<boolean> {
    const capsule = await prisma.cim_offline_capsules.findUnique({
      where: { capsuleId },
    });

    if (!capsule) {
      return false;
    }

    if (capsule.globalSyncStatus !== 'recognized') {
      return false;
    }

    // Check expiry window
    const expiryTime = new Date(
      capsule.timestamp.getTime() + capsule.expiryWindow * 1000
    );

    if (new Date() > expiryTime) {
      await prisma.cim_offline_capsules.update({
        where: { capsuleId },
        data: {
          globalSyncStatus: 'rejected',
        },
      });
      return false;
    }

    // Verify signature
    const payload = {
      capsuleId: capsule.capsuleId,
      sourceSovereignBankId: capsule.sourceSovereignBankId,
      targetSovereignBankId: capsule.targetSovereignBankId,
      senderWalletId: capsule.senderWalletId,
      receiverWalletId: capsule.receiverWalletId,
      amount: capsule.amount.toString(),
      timestamp: capsule.timestamp.toISOString(),
      doubleSpendToken: capsule.doubleSpendToken,
      expiryWindow: capsule.expiryWindow,
    };

    const expectedSignature = this.generateCapsuleSignature(payload);

    if (capsule.signature !== expectedSignature) {
      await prisma.cim_offline_capsules.update({
        where: { capsuleId },
        data: {
          globalSyncStatus: 'rejected',
        },
      });
      return false;
    }

    // Sync capsule
    await prisma.cim_offline_capsules.update({
      where: { capsuleId },
      data: {
        globalSyncStatus: 'synced',
        syncedAt: new Date(),
      },
    });

    // Also sync to regular offline capsule registry
    await prisma.cbdc_offline_capsules.upsert({
      where: { capsuleId },
      update: {
        status: 'synced',
        syncedAt: new Date(),
      },
      create: {
        id: uuidv4(),
        capsuleId,
        senderWalletId: capsule.senderWalletId,
        receiverWalletId: capsule.receiverWalletId,
        amount: capsule.amount,
        timestamp: capsule.timestamp,
        expiryWindow: capsule.expiryWindow,
        doubleSpendToken: capsule.doubleSpendToken,
        signature: capsule.signature,
        status: 'synced',
        syncedAt: new Date(),
      },
    });

    return true;
  }

  /**
   * Get capsules for synchronization
   */
  async getPendingCapsules(
    sovereignBankId?: string,
    limit: number = 100
  ) {
    return await prisma.cim_offline_capsules.findMany({
      where: {
        ...(sovereignBankId && {
          OR: [
            { sourceSovereignBankId: sovereignBankId },
            { targetSovereignBankId: sovereignBankId },
          ],
        }),
        globalSyncStatus: {
          in: ['pending', 'recognized'],
        },
      },
      orderBy: { createdAt: 'asc' },
      take: limit,
    });
  }

  /**
   * Get double-spend registry status
   */
  async getDoubleSpendRegistryStatus(doubleSpendToken: string) {
    const crossSovereignCapsule = await prisma.cim_offline_capsules.findFirst({
      where: { doubleSpendToken },
    });

    const regularCapsule = await prisma.cbdc_offline_capsules.findFirst({
      where: { doubleSpendToken },
    });

    return {
      exists: !!(crossSovereignCapsule || regularCapsule),
      crossSovereignCapsule,
      regularCapsule,
    };
  }
}

export const cimOfflineService = new CimOfflineService();

