// GRU Bond Market Service
// Primary, Supranational, Sovereign, Institutional, Retail markets

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


export type MarketLayer = 'primary' | 'supranational' | 'sovereign' | 'institutional' | 'retail';
export type ParticipantType = 'scb' | 'supranational' | 'institutional' | 'retail' | 'quantum_node' | 'holographic_node';

export interface CreateMarketRequest {
  marketLayer: MarketLayer;
  marketName: string;
  description: string;
  minInvestment?: string;
  maxInvestment?: string;
  participantTypes: ParticipantType[];
}

export interface RegisterParticipantRequest {
  marketId: string;
  sovereignBankId?: string;
  participantType: ParticipantType;
  participantName: string;
  accessLevel: 'full' | 'limited' | 'synthetic_only';
}

export interface ListBondRequest {
  marketId: string;
  bondId?: string;
  syntheticBondId?: string;
  listingType: 'primary' | 'secondary';
  listingPrice?: string;
  quantity?: string;
}

export class BondMarketService {
  /**
   * Create bond market
   */
  async createMarket(request: CreateMarketRequest): Promise<string> {
    logger.info('GRU: Creating bond market', { request });

    const marketId = `MARKET-${request.marketLayer.toUpperCase()}-${uuidv4()}`;

    const market = await prisma.gru_bond_markets.create({
      data: {
        id: uuidv4(),
        marketId,
        marketLayer: request.marketLayer,
        marketName: request.marketName,
        description: request.description,
        minInvestment: request.minInvestment ? new Decimal(request.minInvestment) : null,
        maxInvestment: request.maxInvestment ? new Decimal(request.maxInvestment) : null,
        participantTypes: JSON.stringify(request.participantTypes),
        status: 'active',
        createdAt: new Date(),
        updatedAt: new Date(),
      },
    });

    logger.info('GRU: Bond market created', { marketId });

    return marketId;
  }

  /**
   * Register market participant
   */
  async registerParticipant(request: RegisterParticipantRequest): Promise<string> {
    logger.info('GRU: Registering market participant', { request });

    // Verify market exists
    const market = await prisma.gru_bond_markets.findUnique({
      where: { marketId: request.marketId },
    });

    if (!market) {
      throw new Error(`Market not found: ${request.marketId}`);
    }

    // Verify participant type is allowed
    const allowedTypes: ParticipantType[] = JSON.parse(market.participantTypes as string);
    if (!allowedTypes.includes(request.participantType)) {
      throw new Error(`Participant type not allowed in this market: ${request.participantType}`);
    }

    const participantId = `PART-${uuidv4()}`;

    const participant = await prisma.bondMarketParticipant.create({
      data: {
        participantId,
        marketId: request.marketId,
        sovereignBankId: request.sovereignBankId,
        participantType: request.participantType,
        participantName: request.participantName,
        accessLevel: request.accessLevel,
        status: 'active',
        createdAt: new Date(),
        updatedAt: new Date(),
        approvedAt: new Date(),
      },
    });

    logger.info('GRU: Market participant registered', { participantId });

    return participantId;
  }

  /**
   * List bond on market
   */
  async listBond(request: ListBondRequest): Promise<string> {
    logger.info('GRU: Listing bond on market', { request });

    // Verify market exists
    const market = await prisma.gru_bond_markets.findUnique({
      where: { marketId: request.marketId },
    });

    if (!market) {
      throw new Error(`Market not found: ${request.marketId}`);
    }

    // Verify bond exists
    if (request.bondId) {
      const bond = await prisma.gru_bonds.findUnique({
        where: { bondId: request.bondId },
      });
      if (!bond) {
        throw new Error(`Bond not found: ${request.bondId}`);
      }
    }

    if (request.syntheticBondId) {
      const syntheticBond = await prisma.synthetic_gru_bonds.findUnique({
        where: { syntheticBondId: request.syntheticBondId },
      });
      if (!syntheticBond) {
        throw new Error(`Synthetic bond not found: ${request.syntheticBondId}`);
      }
    }

    const listingId = `LIST-${uuidv4()}`;

    const listing = await prisma.bond_market_listings.create({
      data: {
        id: uuidv4(),
        listingId,
        marketId: request.marketId,
        bondId: request.bondId,
        syntheticBondId: request.syntheticBondId,
        listingType: request.listingType,
        listingPrice: request.listingPrice ? new Decimal(request.listingPrice) : null,
        quantity: request.quantity ? new Decimal(request.quantity) : null,
        status: 'active',
        createdAt: new Date(),
        updatedAt: new Date(),
        listedAt: new Date(),
      },
    });

    logger.info('GRU: Bond listed on market', { listingId });

    return listingId;
  }

  /**
   * Get market by ID
   */
  async getMarket(marketId: string) {
    return await prisma.gru_bond_markets.findUnique({
      where: { marketId },
      include: {
        participants: true,
        bondListings: {
          where: { status: 'active' },
          take: 100,
        },
      },
    });
  }

  /**
   * Get markets by layer
   */
  async getMarketsByLayer(layer: MarketLayer) {
    return await prisma.gru_bond_markets.findMany({
      where: {
        marketLayer: layer,
        status: 'active',
        createdAt: new Date(),
        updatedAt: new Date(),
      },
      include: {
        participants: true,
        bondListings: {
          where: { status: 'active' },
        },
      },
    });
  }

  /**
   * Get all active markets
   */
  async getAllMarkets() {
    return await prisma.gru_bond_markets.findMany({
      where: { status: 'active' },
      include: {
        participants: true,
        bondListings: {
          where: { status: 'active' },
        },
      },
      orderBy: { marketLayer: 'asc' },
    });
  }

  /**
   * Fill listing (mark as filled)
   */
  async fillListing(listingId: string): Promise<void> {
    await prisma.bond_market_listings.update({
      where: { listingId },
      data: {
        status: 'filled',
        filledAt: new Date(),
        updatedAt: new Date(),
      },
    });

    logger.info('GRU: Bond listing filled', { listingId });
  }

  /**
   * Cancel listing
   */
  async cancelListing(listingId: string): Promise<void> {
    await prisma.bond_market_listings.update({
      where: { listingId },
      data: {
        status: 'cancelled',
        updatedAt: new Date(),
      },
    });

    logger.info('GRU: Bond listing cancelled', { listingId });
  }
}

export const bondMarketService = new BondMarketService();

