// PSG State Sync Service
// Global sync via DBIS State Blocks

import prisma from '@/shared/database/prisma';
import { psgEpochEngineService } from './psg-epoch-engine.service';


export class PsgStateSyncService {
  /**
   * Sync state blocks across nodes
   */
  async syncStateBlocks(sourceNodeId: string, targetNodeIds: string[]) {
    const sourceBlock = await prisma.psg_state_blocks.findFirst({
      where: {
        nodeId: sourceNodeId,
      },
      orderBy: {
        createdAt: 'desc',
      },
    });

    if (!sourceBlock) {
      throw new Error(`No state block found for node: ${sourceNodeId}`);
    }

    const syncResults = [];

    for (const targetNodeId of targetNodeIds) {
      try {
        // Create sync block on target node
        const syncedBlock = await prisma.psg_state_blocks.create({
          data: {
            blockId: `SYNC-${sourceBlock.blockId}-${targetNodeId}`,
            epochId: sourceBlock.epochId,
            nodeId: targetNodeId,
            scbBlocks: sourceBlock.scbBlocks,
            cbdcTransactions: sourceBlock.cbdcTransactions,
            commodityTransactions: sourceBlock.commodityTransactions,
            securityTransactions: sourceBlock.securityTransactions,
            stateHash: sourceBlock.stateHash,
            previousBlockHash: sourceBlock.previousBlockHash,
            status: 'committed',
            committedAt: new Date(),
          },
        });

        // Update node sync timestamp
        await prisma.psg_sovereign_nodes.update({
          where: { nodeId: targetNodeId },
          data: {
            lastSyncAt: new Date(),
          },
        });

        syncResults.push({
          targetNodeId,
          status: 'synced',
          blockId: syncedBlock.blockId,
        });
      } catch (error) {
        syncResults.push({
          targetNodeId,
          status: 'failed',
          error: error instanceof Error ? error.message : 'Unknown error',
        });
      }
    }

    return syncResults;
  }

  /**
   * Get node state blocks
   */
  async getNodeStateBlocks(nodeId: string, limit: number = 100) {
    return await prisma.psg_state_blocks.findMany({
      where: { nodeId },
      orderBy: {
        createdAt: 'desc',
      },
      take: limit,
    });
  }

  /**
   * Verify state block consistency
   */
  async verifyStateConsistency(nodeIds: string[]) {
    const nodeBlocks = [];

    for (const nodeId of nodeIds) {
      const block = await prisma.psg_state_blocks.findFirst({
        where: { nodeId },
        orderBy: {
          createdAt: 'desc',
        },
      });

      if (block) {
        nodeBlocks.push({
          nodeId,
          stateHash: block.stateHash,
          blockId: block.blockId,
          epochId: block.epochId,
        });
      }
    }

    // Check if all nodes have same state hash
    const hashes = nodeBlocks.map((nb) => nb.stateHash);
    const uniqueHashes = new Set(hashes);
    const isConsistent = uniqueHashes.size === 1;

    return {
      isConsistent,
      nodeStates: nodeBlocks,
      consensusHash: isConsistent ? hashes[0] : null,
    };
  }

  /**
   * Sync epoch across nodes
   */
  async syncEpoch(epochId: string, targetNodeIds: string[]) {
    const epoch = await prisma.settlement_epochs.findUnique({
      where: { epochId },
      include: {
        stateBlocks: true,
      },
    });

    if (!epoch) {
      throw new Error(`Epoch not found: ${epochId}`);
    }

    const syncResults = [];

    for (const targetNodeId of targetNodeIds) {
      try {
        // Create epoch on target node
        const syncedEpoch = await prisma.settlement_epochs.create({
          data: {
            epochId: `${epochId}-${targetNodeId}`,
            gridId: epoch.gridId,
            nodeId: targetNodeId,
            assetType: epoch.assetType,
            epochInterval: epoch.epochInterval,
            epochNumber: epoch.epochNumber,
            stateHash: epoch.stateHash,
            status: epoch.status,
            committedAt: epoch.committedAt,
          },
        });

        syncResults.push({
          targetNodeId,
          status: 'synced',
          epochId: syncedEpoch.epochId,
        });
      } catch (error) {
        syncResults.push({
          targetNodeId,
          status: 'failed',
          error: error instanceof Error ? error.message : 'Unknown error',
        });
      }
    }

    return syncResults;
  }
}

export const psgStateSyncService = new PsgStateSyncService();

