/**
 * OTC Trade Persistence Service
 * Persists Crypto.com OTC deals to the database for reconciliation and reporting
 */

import { Decimal } from '@prisma/client/runtime/library';
import { v4 as uuidv4 } from 'uuid';
import prisma from '@/shared/database/prisma';
import { Deal } from '../types';
import { logger } from '@/infrastructure/monitoring/logger';

export class OtcTradePersistenceService {
  private enabled: boolean = true;

  /**
   * Enable or disable persistence
   */
  setEnabled(enabled: boolean): void {
    this.enabled = enabled;
  }

  /**
   * Persist or update OTC deal
   */
  async persistDeal(deal: Deal, sovereignBankId?: string): Promise<void> {
    if (!this.enabled) return;

    try {
      const leg = deal.leg_list?.[0];
      if (!leg) {
        logger.warn('[OtcPersistence] Deal has no legs', { dealId: deal.deal_id });
        return;
      }

      const data = {
        id: uuidv4(),
        dealId: deal.deal_id,
        clDealId: deal.cl_deal_id || deal.deal_id,
        quoteId: deal.quote_id,
        quoteReqId: deal.quote_req_id,
        sovereignBankId: sovereignBankId ?? null,
        instrumentName: leg.instrument_name,
        side: leg.side,
        quantity: leg.quantity ? new Decimal(leg.quantity) : null,
        notional: leg.notional ? new Decimal(leg.notional) : null,
        price: new Decimal(leg.price),
        dealStatus: deal.deal_status,
        settlementArrangement: deal.settlement_arrangement ?? null,
        createTimeNs: deal.create_time_ns ?? null,
        updateTimeNs: deal.update_time_ns,
        settleTimeNs: deal.settle_time_ns ?? null,
        legData: deal.leg_list as unknown as object,
      };

      await prisma.otc_trades.upsert({
        where: { dealId: deal.deal_id },
        create: data,
        update: {
          dealStatus: deal.deal_status,
          updateTimeNs: deal.update_time_ns,
          settleTimeNs: deal.settle_time_ns ?? null,
          quantity: leg.executed_quantity ? new Decimal(leg.executed_quantity) : data.quantity,
          notional: leg.executed_notional ? new Decimal(leg.executed_notional) : data.notional,
          legData: deal.leg_list as unknown as object,
          updatedAt: new Date(),
        },
      });

      logger.info('[OtcPersistence] Persisted deal', {
        dealId: deal.deal_id,
        status: deal.deal_status,
      });
    } catch (error) {
      // Gracefully handle missing otc_trades table (migration not run)
      const errMsg = error instanceof Error ? error.message : String(error);
      if (errMsg.includes('otc_trades') || errMsg.includes('does not exist')) {
        logger.warn('[OtcPersistence] otc_trades table not available - run prisma migrate');
        return;
      }
      logger.error('[OtcPersistence] Failed to persist deal', {
        dealId: deal.deal_id,
        error: errMsg,
      });
    }
  }

  /**
   * Link OTC deal to FX trade
   */
  async linkToFxTrade(dealId: string, fxTradeId: string): Promise<void> {
    if (!this.enabled) return;

    try {
      await prisma.otc_trades.update({
        where: { dealId },
        data: { fxTradeId, updatedAt: new Date() },
      });
      logger.info('[OtcPersistence] Linked OTC deal to FX trade', {
        dealId,
        fxTradeId,
      });
    } catch (error) {
      logger.error('[OtcPersistence] Failed to link deal', {
        dealId,
        error: error instanceof Error ? error.message : String(error),
      });
    }
  }
}

export const otcTradePersistenceService = new OtcTradePersistenceService();
