// PSG Epoch Engine Service
// Settlement epoch management (1s CBDC/fiat, 5s commodities, 10s securities)

import prisma from '@/shared/database/prisma';
import { createHash } from 'crypto';
import { v4 as uuidv4 } from 'uuid';
import { psgMasterGridService } from './psg-master-grid.service';


export interface EpochCommitData {
  scbBlocks: Record<string, unknown>[];
  cbdcTransactions?: Record<string, unknown>[];
  commodityTransactions?: Record<string, unknown>[];
  securityTransactions?: Record<string, unknown>[];
}

export class PsgEpochEngineService {
  private epochIntervals = {
    cbdc_fiat: 1, // 1 second
    commodity: 5, // 5 seconds
    security: 10, // 10 seconds
  };

  /**
   * Create settlement epoch
   */
  async createEpoch(
    assetType: string,
    commitData: EpochCommitData,
    nodeId?: string
  ) {
    const grid = await psgMasterGridService.initializeMasterGrid();
    const epochInterval = this.epochIntervals[assetType as keyof typeof this.epochIntervals] || 1;

    // Get next epoch number
    const lastEpoch = await prisma.settlementEpoch.findFirst({
      where: {
        gridId: grid.gridId,
        assetType,
      },
      orderBy: {
        epochNumber: 'desc',
      },
    });

    const epochNumber = lastEpoch ? lastEpoch.epochNumber + 1 : 1;

    // Calculate state hash: HASH(SCB_blocks + CBDC_tx + Commodity_tx + Security_tx)
    const stateHash = this.calculateStateHash(commitData);

    const epochId = `EPOCH-${assetType}-${epochNumber}-${uuidv4()}`;

    const epoch = await prisma.settlementEpoch.create({
      data: {
        epochId,
        gridId: grid.gridId,
        nodeId,
        assetType,
        epochInterval,
        epochNumber,
        stateHash,
        status: 'committed',
        committedAt: new Date(),
      },
    });

    // Create state block
    await this.createStateBlock(epochId, nodeId, commitData, stateHash);

    // Update grid consensus
    await psgMasterGridService.updateConsensus();

    return epoch;
  }

  /**
   * Calculate state hash
   */
  private calculateStateHash(commitData: EpochCommitData): string {
    const dataString = JSON.stringify({
      scbBlocks: commitData.scbBlocks,
      cbdcTransactions: commitData.cbdcTransactions || [],
      commodityTransactions: commitData.commodityTransactions || [],
      securityTransactions: commitData.securityTransactions || [],
    });

    return createHash('sha256').update(dataString).digest('hex');
  }

  /**
   * Create state block for epoch
   */
  async createStateBlock(
    epochId: string,
    nodeId: string | undefined,
    commitData: EpochCommitData,
    stateHash: string
  ) {
    const lastBlock = await prisma.psgStateBlock.findFirst({
      where: {
        nodeId: nodeId || undefined,
      },
      orderBy: {
        createdAt: 'desc',
      },
    });

    const previousBlockHash = lastBlock?.stateHash || null;

    const blockId = `PSG-BLOCK-${uuidv4()}`;

    return await prisma.psgStateBlock.create({
      data: {
        blockId,
        epochId,
        nodeId,
        scbBlocks: commitData.scbBlocks,
        cbdcTransactions: commitData.cbdcTransactions || [],
        commodityTransactions: commitData.commodityTransactions || [],
        securityTransactions: commitData.securityTransactions || [],
        stateHash,
        previousBlockHash,
        status: 'committed',
        committedAt: new Date(),
      },
    });
  }

  /**
   * Get epoch by ID
   */
  async getEpoch(epochId: string) {
    return await prisma.settlementEpoch.findUnique({
      where: { epochId },
      include: {
        stateBlocks: true,
      },
    });
  }

  /**
   * Get recent epochs
   */
  async getRecentEpochs(assetType?: string, limit: number = 100) {
    const where: any = {};
    if (assetType) {
      where.assetType = assetType;
    }

    return await prisma.settlementEpoch.findMany({
      where,
      orderBy: {
        committedAt: 'desc',
      },
      take: limit,
    });
  }

  /**
   * Get epoch interval for asset type
   */
  getEpochInterval(assetType: string): number {
    return this.epochIntervals[assetType as keyof typeof this.epochIntervals] || 1;
  }
}

export const psgEpochEngineService = new PsgEpochEngineService();

