// Reserve Certificate Service
// Physical reserve certificate generation
// Certificate hash: HASH256(...)
// Custodian verification
// Reserve audit tracking

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 ReserveCertificateRequest {
  commodityType: string;
  quantity: string;
  unit: string;
  custodianId: string;
}

export interface CertificateVerification {
  certificateId: string;
  verificationStatus: string;
  isValid: boolean;
  custodianId: string;
}

export class ReserveCertificateService {
  /**
   * Create reserve certificate
   */
  async createReserveCertificate(
    request: ReserveCertificateRequest
  ): Promise<string> {
    // Verify custodian
    const custodian = await prisma.commodity_custodians.findUnique({
      where: { custodianId: request.custodianId },
    });

    if (!custodian || custodian.approvalStatus !== 'approved') {
      throw new Error('Custodian not approved');
    }

    const certificateId = `RC-${request.commodityType}-${uuidv4()}`;

    // Generate certificate hash: HASH256(...)
    const certificateHash = this.generateCertificateHash({
      certificateId,
      commodityType: request.commodityType,
      quantity: request.quantity,
      unit: request.unit,
      custodianId: request.custodianId,
      timestamp: new Date().toISOString(),
    });

    // Create certificate
    const certificate = await prisma.commodity_reserve_certificates.create({
      data: {
        id: uuidv4(),
        certificateId,
        commodityType: request.commodityType.toUpperCase(),
        quantity: new Decimal(request.quantity),
        unit: request.unit,
        custodianId: request.custodianId,
        certificateHash,
        verificationStatus: 'pending',
        createdAt: new Date(),
        updatedAt: new Date(),
      },
    });

    // Schedule audit
    await this.scheduleAudit(certificate.certificateId);

    return certificate.certificateId;
  }

  /**
   * Generate certificate hash: HASH256(...)
   */
  private generateCertificateHash(
    certificateData: Record<string, unknown>
  ): string {
    const dataString = JSON.stringify(certificateData);
    return createHash('sha256').update(dataString).digest('hex');
  }

  /**
   * Verify reserve certificate
   */
  async verifyCertificate(
    certificateId: string
  ): Promise<CertificateVerification | null> {
    const certificate = await prisma.commodity_reserve_certificates.findUnique({
      where: { certificateId },
      include: {
        commodity_custodians: true,
      },
    });

    if (!certificate) {
      return null;
    }

    // Recalculate hash
    const expectedHash = this.generateCertificateHash({
      certificateId: certificate.certificateId,
      commodityType: certificate.commodityType,
      quantity: certificate.quantity.toString(),
      unit: certificate.unit,
      custodianId: certificate.custodianId,
      timestamp: certificate.createdAt.toISOString(),
    });

    // Verify hash matches
    const isValid = certificate.certificateHash === expectedHash;

    // Check custodian approval
    const custodian = await prisma.commodity_custodians.findUnique({
      where: { custodianId: certificate.custodianId },
    });
    const custodianValid = custodian?.approvalStatus === 'approved';

    const verificationStatus = isValid && custodianValid
      ? 'verified'
      : 'rejected';

    // Update verification status if changed
    if (certificate.verificationStatus !== verificationStatus) {
      await prisma.commodity_reserve_certificates.update({
        where: { certificateId },
        data: {
          verificationStatus,
          auditDate: verificationStatus === 'verified' ? new Date() : null,
        },
      });
    }

    return {
      certificateId: certificate.certificateId,
      verificationStatus,
      isValid: isValid && custodianValid,
      custodianId: certificate.custodianId,
    };
  }

  /**
   * Schedule audit for reserve certificate
   */
  private async scheduleAudit(certificateId: string): Promise<void> {
    // In production, this would schedule a physical audit
    // For now, set next audit date to 1 year from now
    const nextAuditDate = new Date();
    nextAuditDate.setFullYear(nextAuditDate.getFullYear() + 1);

    await prisma.commodity_reserve_certificates.update({
      where: { certificateId },
      data: {
        nextAuditDate,
      },
    });
  }

  /**
   * Perform reserve audit
   */
  async performAudit(certificateId: string): Promise<boolean> {
    const certificate = await prisma.commodity_reserve_certificates.findUnique({
      where: { certificateId },
      include: {
        commodity_custodians: true,
      },
    });

    if (!certificate) {
      return false;
    }

    // In production, this would:
    // 1. Physically verify reserves
    // 2. Check custody records
    // 3. Verify quantities

    // For now, mark as verified
    await prisma.commodity_reserve_certificates.update({
      where: { certificateId },
      data: {
        verificationStatus: 'verified',
        auditDate: new Date(),
        nextAuditDate: new Date(Date.now() + 365 * 24 * 60 * 60 * 1000), // 1 year
      },
    });

    return true;
  }

  /**
   * Get certificate by ID
   */
  async getCertificate(certificateId: string) {
    return await prisma.commodity_reserve_certificates.findUnique({
      where: { certificateId },
      include: {
        commodity_custodians: true,
      },
    });
  }

  /**
   * List certificates by custodian
   */
  async listCertificatesByCustodian(
    custodianId: string,
    verificationStatus?: string
  ) {
    return await prisma.commodity_reserve_certificates.findMany({
      where: {
        custodianId,
        ...(verificationStatus && { verificationStatus }),
      },
      orderBy: { createdAt: 'desc' },
    });
  }

  /**
   * Get certificates due for audit
   */
  async getCertificatesDueForAudit(limit: number = 100) {
    const now = new Date();

    return await prisma.commodity_reserve_certificates.findMany({
      where: {
        OR: [
          {
            nextAuditDate: {
              lte: now,
            },
          },
          {
            auditDate: null,
          },
        ],
        verificationStatus: {
          not: 'rejected',
        },
      },
      orderBy: { nextAuditDate: 'asc' },
      take: limit,
    });
  }
}

export const reserveCertificateService = new ReserveCertificateService();

