// Global Parity Engine (GPE) Service
// parity = fx_weight + commodity_weight + ssu_stability + risk_premium

import prisma from '@/shared/database/prisma';
import { Decimal } from '@prisma/client/runtime/library';
import { v4 as uuidv4 } from 'uuid';


export interface CalculateParityRequest {
  currencyCode: string;
  assetType: string;
  fxWeight: number;
  commodityWeight: number;
  ssuStability: number;
  riskPremium: number;
  umbId?: string;
}

export class GpeService {
  /**
   * Calculate global parity
   * Formula: parity = fx_weight + commodity_weight + ssu_stability + risk_premium
   */
  async calculateParity(request: CalculateParityRequest) {
    const fxWeight = new Decimal(request.fxWeight);
    const commodityWeight = new Decimal(request.commodityWeight);
    const ssuStability = new Decimal(request.ssuStability);
    const riskPremium = new Decimal(request.riskPremium);

    const calculatedParity = fxWeight
      .plus(commodityWeight)
      .plus(ssuStability)
      .plus(riskPremium);

    const parityId = `GPE-${uuidv4()}`;

    const parity = await prisma.global_parity_engines.create({
      data: {
        parityId,
        umbId: request.umbId || null,
        currencyCode: request.currencyCode,
        assetType: request.assetType,
        fxWeight,
        commodityWeight,
        ssuStability,
        riskPremium,
        calculatedParity,
        status: 'active',
        calculatedAt: new Date(),
      },
    });

    return parity;
  }

  /**
   * Get parity by ID
   */
  async getParity(parityId: string) {
    const parity = await prisma.global_parity_engines.findUnique({
      where: { parityId },
      include: {
        umb: true,
        contracts: true,
      },
    });

    if (!parity) {
      throw new Error(`Parity not found: ${parityId}`);
    }

    return parity;
  }

  /**
   * Get parity for currency and asset type
   */
  async getParityForCurrency(currencyCode: string, assetType: string) {
    const parity = await prisma.global_parity_engines.findFirst({
      where: {
        currencyCode,
        assetType,
        status: 'active',
      },
      include: {
        contracts: {
          where: {
            status: 'active',
          },
        },
      },
      orderBy: {
        calculatedAt: 'desc',
      },
    });

    return parity;
  }

  /**
   * Get all parities
   */
  async getAllParities(filters?: {
    currencyCode?: string;
    assetType?: string;
    umbId?: string;
  }) {
    const where: Record<string, unknown> = {
      status: 'active',
    };

    if (filters?.currencyCode) {
      where.currencyCode = filters.currencyCode;
    }
    if (filters?.assetType) {
      where.assetType = filters.assetType;
    }
    if (filters?.umbId) {
      where.umbId = filters.umbId;
    }

    return prisma.global_parity_engines.findMany({
      where,
      include: {
        umb: true,
        _count: {
          select: {
            contracts: true,
          },
        },
      },
      orderBy: {
        calculatedAt: 'desc',
      },
    });
  }

  /**
   * Recalculate parity with updated weights
   */
  async recalculateParity(parityId: string, weights: {
    fxWeight?: number;
    commodityWeight?: number;
    ssuStability?: number;
    riskPremium?: number;
  }) {
    const existing = await prisma.global_parity_engines.findUnique({
      where: { parityId },
    });

    if (!existing) {
      throw new Error(`Parity not found: ${parityId}`);
    }

    const fxWeight = weights.fxWeight !== undefined
      ? new Decimal(weights.fxWeight)
      : existing.fxWeight;
    const commodityWeight = weights.commodityWeight !== undefined
      ? new Decimal(weights.commodityWeight)
      : existing.commodityWeight;
    const ssuStability = weights.ssuStability !== undefined
      ? new Decimal(weights.ssuStability)
      : existing.ssuStability;
    const riskPremium = weights.riskPremium !== undefined
      ? new Decimal(weights.riskPremium)
      : existing.riskPremium;

    const calculatedParity = fxWeight
      .plus(commodityWeight)
      .plus(ssuStability)
      .plus(riskPremium);

    return prisma.global_parity_engines.update({
      where: { parityId },
      data: {
        fxWeight,
        commodityWeight,
        ssuStability,
        riskPremium,
        calculatedParity,
        calculatedAt: new Date(),
      },
    });
  }
}

export const gpeService = new GpeService();

