// DBIS Accounting Standards Service
// Fair value marking, commodity feed integration

import prisma from '@/shared/database/prisma';
import { Decimal } from '@prisma/client/runtime/library';


export interface ValuationData {
  assetType: string;
  assetId: string;
  fairValue: number;
  currencyCode: string;
  valuationDate: Date;
  source: string;
}

export class AccountingStandardsService {
  /**
   * Get valuation rule for asset type
   */
  async getValuationRule(assetType: string) {
    return await prisma.valuationRule.findFirst({
      where: {
        assetType,
        status: 'active',
        effectiveDate: {
          lte: new Date(),
        },
        OR: [
          { expiryDate: null },
          { expiryDate: { gte: new Date() } },
        ],
      },
      orderBy: { effectiveDate: 'desc' },
    });
  }

  /**
   * Mark asset to fair value
   */
  async markToFairValue(assetId: string, assetType: string, fairValue: number, currencyCode: string) {
    const rule = await this.getValuationRule(assetType);
    
    if (!rule) {
      throw new Error(`No valuation rule found for asset type: ${assetType}`);
    }

    // Update asset value based on type
    switch (assetType) {
      case 'commodity':
        await this.updateCommodityValue(assetId, fairValue);
        break;
      case 'security':
        await this.updateSecurityValue(assetId, fairValue);
        break;
      case 'fiat':
      case 'cbdc':
        // Fiat and CBDC are already at fair value
        break;
      default:
        throw new Error(`Unsupported asset type for fair value marking: ${assetType}`);
    }

    // Log valuation
    await prisma.auditLog.create({
      data: {
        eventType: 'valuation',
        entityType: assetType,
        entityId: assetId,
        action: 'mark_to_fair_value',
        details: {
          fairValue,
          currencyCode,
          valuationMethod: rule.valuationMethod,
          timestamp: new Date(),
        },
      },
    });
  }

  /**
   * Update commodity value
   */
  private async updateCommodityValue(commodityId: string, fairValue: number) {
    // In production, would update commodity price
    // For now, update commodity spot price if exists
    const commodity = await prisma.commodity.findFirst({
      where: {
        id: commodityId,
      },
    });

    if (commodity) {
      await prisma.commodity.update({
        where: { id: commodityId },
        data: {
          spotPrice: new Decimal(fairValue),
          lastUpdated: new Date(),
        },
      });
    }
  }

  /**
   * Update security value
   */
  private async updateSecurityValue(securityId: string, fairValue: number) {
    const security = await prisma.security.findFirst({
      where: {
        securityId,
      },
    });

    if (security) {
      await prisma.security.update({
        where: { id: security.id },
        data: {
          price: new Decimal(fairValue),
          updatedAt: new Date(),
        },
      });
    }
  }

  /**
   * Get commodity feed price
   */
  async getCommodityFeedPrice(commodityType: string, unit: string): Promise<number | null> {
    const commodity = await prisma.commodity.findUnique({
      where: {
        commodityType_unit: {
          commodityType,
          unit,
        },
      },
    });

    if (!commodity) {
      return null;
    }

    return parseFloat(commodity.spotPrice.toString());
  }

  /**
   * Get FX reference rate
   */
  async getFXReferenceRate(baseCurrency: string, quoteCurrency: string): Promise<number | null> {
    const fxPair = await prisma.fxPair.findFirst({
      where: {
        OR: [
          {
            baseCurrency,
            quoteCurrency,
          },
          {
            baseCurrency: quoteCurrency,
            quoteCurrency: baseCurrency,
          },
        ],
        status: 'active',
      },
      include: {
        trades: {
          where: {
            status: 'settled',
          },
          orderBy: { timestampUtc: 'desc' },
          take: 1,
        },
      },
    });

    if (!fxPair || fxPair.trades.length === 0) {
      return null;
    }

    return parseFloat(fxPair.trades[0].price.toString());
  }

  /**
   * Create valuation rule
   */
  async createValuationRule(
    assetType: string,
    valuationMethod: string,
    feedSource?: string,
    updateFrequency: string = 'real_time'
  ) {
    return await prisma.valuationRule.create({
      data: {
        id: require('uuid').v4(),
        ruleId: require('uuid').v4(),
        assetType,
        valuationMethod,
        feedSource,
        updateFrequency,
        status: 'active',
        effectiveDate: new Date(),
      },
    });
  }
}

export const accountingStandardsService = new AccountingStandardsService();

