// State Block Service
// Hash-lock generation: SHA3(tx_payload + sovereign_signature)
// State block creation
// Finality enforcement
// Block verification and unlocking

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


export interface StateBlockRequest {
  nodeId: string;
  transactionPayload: Record<string, unknown>;
  sovereignSignature: string;
}

export interface StateBlockResult {
  blockId: string;
  hashLock: string;
  blockHash: string;
  status: string;
}

export class StateBlockService {
  /**
   * Create state block with hash-lock
   * hash_lock = SHA3(tx_payload + sovereign_signature)
   */
  async createStateBlock(
    request: StateBlockRequest
  ): Promise<StateBlockResult> {
    const blockId = `BLOCK-${uuidv4()}`;

    // Generate hash-lock: SHA3(tx_payload + sovereign_signature)
    const hashLock = this.generateHashLock(
      request.transactionPayload,
      request.sovereignSignature
    );

    // Get previous block hash
    const previousBlock = await prisma.state_blocks.findFirst({
      where: {
        nodeId: request.nodeId,
        status: 'final',
      },
      orderBy: { createdAt: 'desc' },
    });

    // Generate block hash
    const blockData = {
      blockId,
      nodeId: request.nodeId,
      transactionPayload: request.transactionPayload,
      sovereignSignature: request.sovereignSignature,
      hashLock,
      previousBlockHash: previousBlock?.blockHash || null,
      timestamp: new Date().toISOString(),
    };

    const blockHash = this.hashBlock(blockData);

    // Create state block
    const stateBlock = await prisma.state_blocks.create({
      data: {
        blockId,
        nodeId: request.nodeId,
        transactionPayload: request.transactionPayload as any,
        sovereignSignature: request.sovereignSignature,
        hashLock,
        blockHash,
        previousBlockHash: previousBlock?.blockHash || null,
        status: 'locked',
      },
    });

    return {
      blockId: stateBlock.blockId,
      hashLock: stateBlock.hashLock,
      blockHash: stateBlock.blockHash,
      status: stateBlock.status,
    };
  }

  /**
   * Generate hash-lock: SHA3(tx_payload + sovereign_signature)
   */
  private generateHashLock(
    transactionPayload: Record<string, unknown>,
    sovereignSignature: string
  ): string {
    const payloadString = JSON.stringify(transactionPayload);
    const combined = payloadString + sovereignSignature;
    return createHash('sha3-256').update(combined).digest('hex');
  }

  /**
   * Hash block data
   */
  private hashBlock(blockData: Record<string, unknown>): string {
    const blockString = JSON.stringify(blockData);
    return createHash('sha3-256').update(blockString).digest('hex');
  }

  /**
   * Verify hash-lock
   */
  async verifyHashLock(
    blockId: string,
    transactionPayload: Record<string, unknown>,
    sovereignSignature: string
  ): Promise<boolean> {
    const block = await prisma.state_blocks.findUnique({
      where: { blockId },
    });

    if (!block) {
      return false;
    }

    const expectedHashLock = this.generateHashLock(
      transactionPayload,
      sovereignSignature
    );

    return block.hashLock === expectedHashLock;
  }

  /**
   * Unlock state block (when both ledgers match)
   */
  async unlockStateBlock(blockId: string): Promise<boolean> {
    const block = await prisma.state_blocks.findUnique({
      where: { blockId },
    });

    if (!block || block.status !== 'locked') {
      return false;
    }

    // Verify hash-lock matches
    const isValid = await this.verifyHashLock(
      blockId,
      block.transactionPayload as Record<string, unknown>,
      block.sovereignSignature
    );

    if (!isValid) {
      return false;
    }

    // Update status to unlocked (ready for finalization)
    await prisma.state_blocks.update({
      where: { blockId },
      data: {
        status: 'unlocked',
      },
    });

    return true;
  }

  /**
   * Finalize state block (enforce finality)
   */
  async finalizeStateBlock(blockId: string): Promise<boolean> {
    const block = await prisma.state_blocks.findUnique({
      where: { blockId },
    });

    if (!block || block.status !== 'unlocked') {
      return false;
    }

    // Finalize block
    await prisma.state_blocks.update({
      where: { blockId },
      data: {
        status: 'final',
        finalizedAt: new Date(),
      },
    });

    return true;
  }

  /**
   * Get state blocks for a node
   */
  async getStateBlocks(nodeId: string, status?: string, limit: number = 100) {
    return await prisma.state_blocks.findMany({
      where: {
        nodeId,
        ...(status && { status }),
      },
      orderBy: { createdAt: 'desc' },
      take: limit,
    });
  }

  /**
   * Get state block by ID
   */
  async getStateBlock(blockId: string) {
    return await prisma.state_blocks.findUnique({
      where: { blockId },
    });
  }

  /**
   * Get latest state block for a node
   */
  async getLatestStateBlock(nodeId: string) {
    return await prisma.state_blocks.findFirst({
      where: {
        nodeId,
        status: 'final',
      },
      orderBy: { createdAt: 'desc' },
    });
  }

  /**
   * Enforce finality - ensure block cannot be reversed
   */
  async enforceFinality(blockId: string): Promise<boolean> {
    const block = await prisma.state_blocks.findUnique({
      where: { blockId },
    });

    if (!block) {
      return false;
    }

    // Once finalized, block cannot be reversed
    if (block.status === 'final' && block.finalizedAt) {
      return true;
    }

    // Finalize if unlocked
    if (block.status === 'unlocked') {
      return await this.finalizeStateBlock(blockId);
    }

    return false;
  }
}

export const stateBlockService = new StateBlockService();

