// AS4 Payload Vault Service
// Immutable WORM storage for evidence (payloads, signatures, receipts)

import { v4 as uuidv4 } from 'uuid';
import prisma from '@/shared/database/prisma';
import { as4SecurityService } from './as4-security.service';
import { logger } from '@/infrastructure/monitoring/logger';

export interface PayloadVaultEntry {
  vaultId: string;
  instructionId?: string;
  messageId: string;
  payloadHash: string;
  payloadData: string; // Encrypted
  payloadType: 'INSTRUCTION' | 'ADVICE' | 'RECEIPT';
  memberId: string;
  createdAt: Date;
}

export class As4PayloadVaultService {
  /**
   * Store payload in vault (WORM - Write Once Read Many)
   */
  async storePayload(data: {
    instructionId?: string;
    messageId: string;
    payload: string;
    payloadType: 'INSTRUCTION' | 'ADVICE' | 'RECEIPT';
    memberId: string;
  }): Promise<PayloadVaultEntry> {
    // Calculate payload hash
    const payloadHash = as4SecurityService.calculatePayloadHash(data.payload);

    // Check if already stored (idempotency)
    const existing = await prisma.as4PayloadVault.findFirst({
      where: {
        messageId: data.messageId,
        payloadHash,
        payloadType: data.payloadType,
      },
    });

    if (existing) {
      logger.info('Payload already in vault', {
        vaultId: existing.vaultId,
        messageId: data.messageId,
      });
      return {
        vaultId: existing.vaultId,
        instructionId: existing.instructionId || undefined,
        messageId: existing.messageId,
        payloadHash: existing.payloadHash,
        payloadData: existing.payloadData,
        payloadType: existing.payloadType as 'INSTRUCTION' | 'ADVICE' | 'RECEIPT',
        memberId: existing.memberId,
        createdAt: existing.createdAt,
      };
    }

    // TODO: Encrypt payload before storage
    // For now, store as base64
    const encryptedPayload = Buffer.from(data.payload).toString('base64');

    const vault = await prisma.as4PayloadVault.create({
      data: {
        id: uuidv4(),
        vaultId: `VAULT-${uuidv4()}`,
        instructionId: data.instructionId,
        messageId: data.messageId,
        payloadHash,
        payloadData: encryptedPayload,
        payloadType: data.payloadType,
        memberId: data.memberId,
      },
    });

    logger.info('Payload stored in vault', {
      vaultId: vault.vaultId,
      messageId: data.messageId,
      payloadType: data.payloadType,
    });

    return {
      vaultId: vault.vaultId,
      instructionId: vault.instructionId || undefined,
      messageId: vault.messageId,
      payloadHash: vault.payloadHash,
      payloadData: vault.payloadData,
      payloadType: vault.payloadType as 'INSTRUCTION' | 'ADVICE' | 'RECEIPT',
      memberId: vault.memberId,
      createdAt: vault.createdAt,
    };
  }

  /**
   * Retrieve payload from vault
   */
  async retrievePayload(vaultId: string): Promise<string | null> {
    const vault = await prisma.as4PayloadVault.findUnique({
      where: { vaultId },
    });

    if (!vault) {
      return null;
    }

    // TODO: Decrypt payload
    // For now, decode base64
    return Buffer.from(vault.payloadData, 'base64').toString('utf-8');
  }

  /**
   * Retrieve payload by message ID
   */
  async retrievePayloadByMessageId(
    messageId: string,
    payloadType?: 'INSTRUCTION' | 'ADVICE' | 'RECEIPT'
  ): Promise<PayloadVaultEntry[]> {
    const where: any = { messageId };
    if (payloadType) {
      where.payloadType = payloadType;
    }

    const vaults = await prisma.as4PayloadVault.findMany({
      where,
      orderBy: { createdAt: 'desc' },
    });

    return vaults.map((v) => ({
      vaultId: v.vaultId,
      instructionId: v.instructionId || undefined,
      messageId: v.messageId,
      payloadHash: v.payloadHash,
      payloadData: v.payloadData,
      payloadType: v.payloadType as 'INSTRUCTION' | 'ADVICE' | 'RECEIPT',
      memberId: v.memberId,
      createdAt: v.createdAt,
    }));
  }

  /**
   * Verify payload hash
   */
  async verifyPayloadHash(vaultId: string, expectedHash: string): Promise<boolean> {
    const vault = await prisma.as4PayloadVault.findUnique({
      where: { vaultId },
    });

    if (!vault) {
      return false;
    }

    return vault.payloadHash.toUpperCase() === expectedHash.toUpperCase();
  }

  /**
   * Get vault entries for instruction
   */
  async getInstructionVaultEntries(instructionId: string): Promise<PayloadVaultEntry[]> {
    const vaults = await prisma.as4PayloadVault.findMany({
      where: { instructionId },
      orderBy: { createdAt: 'asc' },
    });

    return vaults.map((v) => ({
      vaultId: v.vaultId,
      instructionId: v.instructionId || undefined,
      messageId: v.messageId,
      payloadHash: v.payloadHash,
      payloadData: v.payloadData,
      payloadType: v.payloadType as 'INSTRUCTION' | 'ADVICE' | 'RECEIPT',
      memberId: v.memberId,
      createdAt: v.createdAt,
    }));
  }
}

export const as4PayloadVaultService = new As4PayloadVaultService();
