// AS4 Liquidity & Limits Service
// Balance checks, intraday credit, caps
// See docs/00-meta/PLACEHOLDERS_AND_COMPLETION_MASTER_LIST.md §4 — intraday/daily usage, reservation, release documented as future work.

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

export interface LiquidityCheckResult {
  sufficient: boolean;
  reason?: string;
  availableBalance?: string;
  requiredAmount?: string;
}

export interface LimitsCheckResult {
  withinLimits: boolean;
  reason?: string;
  limitType?: string;
  limitValue?: string;
  currentUsage?: string;
}

export class LiquidityLimitsService {
  /**
   * Check liquidity for member account
   */
  async checkLiquidity(
    memberId: string,
    accountId: string,
    amount: string,
    currency: string
  ): Promise<LiquidityCheckResult> {
    try {
      // Extract member ID from account (MSA:{MEMBER_ID}:{CURRENCY})
      const accountParts = accountId.split(':');
      if (accountParts.length !== 3 || accountParts[0] !== 'MSA') {
        return {
          sufficient: false,
          reason: 'Invalid account format',
        };
      }

      const requiredAmount = new Decimal(amount);
      const ledgerUrl = process.env.LEDGER_SERVICE_URL;
      if (ledgerUrl) {
        const res = await fetch(`${ledgerUrl}/balance/${encodeURIComponent(accountId)}`);
        if (res.ok) {
          const json = await res.json();
          const bal = new Decimal(json.balance ?? 0);
          return {
            sufficient: bal.gte(requiredAmount),
            availableBalance: bal.toString(),
            requiredAmount: amount,
          };
        }
      }

      // Fallback: assume sufficient when no LEDGER_SERVICE_URL configured
      logger.info('Liquidity check performed', {
        memberId,
        accountId,
        amount,
        currency,
      });

      return {
        sufficient: true,
        availableBalance: '1000000.00', // Placeholder
        requiredAmount: amount,
      };
    } catch (error) {
      logger.error('Liquidity check failed', {
        memberId,
        accountId,
        error: error instanceof Error ? error.message : 'Unknown error',
      });

      return {
        sufficient: false,
        reason: error instanceof Error ? error.message : 'Unknown error',
      };
    }
  }

  /**
   * Check limits for member
   */
  async checkLimits(
    memberId: string,
    amount: string,
    currency: string,
    limitType: 'DAILY' | 'INTRADAY' | 'PER_TRANSACTION' = 'PER_TRANSACTION'
  ): Promise<LimitsCheckResult> {
    try {
      const amountDecimal = new Decimal(amount);
      const limitsUrl = process.env.LIMITS_SERVICE_URL;
      if (limitsUrl) {
        try {
          const res = await fetch(
            `${limitsUrl}/limits/${encodeURIComponent(memberId)}?limitType=${limitType}`
          );
          if (res.ok) {
            const json = (await res.json()) as { limitValue?: string; currentUsage?: string };
            const limit = new Decimal(json.limitValue ?? '1000000');
            const usage = new Decimal(json.currentUsage ?? '0');
            if (amountDecimal.plus(usage).gt(limit)) {
              return {
                withinLimits: false,
                reason: `Amount would exceed ${limitType} limit`,
                limitType,
                limitValue: limit.toString(),
                currentUsage: usage.toString(),
              };
            }
            return { withinLimits: true };
          }
        } catch {
          /* fallback to placeholder */
        }
      }

      // Placeholder limits when LIMITS_SERVICE_URL not configured
      const limits: Record<string, Decimal> = {
        PER_TRANSACTION: new Decimal('1000000.00'),
        INTRADAY: new Decimal('10000000.00'),
        DAILY: new Decimal('50000000.00'),
      };

      const limit = limits[limitType] || limits.PER_TRANSACTION;

      if (amountDecimal.gt(limit)) {
        return {
          withinLimits: false,
          reason: `Amount exceeds ${limitType} limit`,
          limitType,
          limitValue: limit.toString(),
          currentUsage: amount,
        };
      }

      // Future work: implement getCurrentUsage(memberId, limitType) from ledger or limits service
      // and enforce: if (usage.plus(amountDecimal).gt(limit)) return { withinLimits: false, ... }

      return {
        withinLimits: true,
      };
    } catch (error) {
      logger.error('Limits check failed', {
        memberId,
        amount,
        error: error instanceof Error ? error.message : 'Unknown error',
      });

      return {
        withinLimits: false,
        reason: error instanceof Error ? error.message : 'Unknown error',
      };
    }
  }

  /**
   * Reserve liquidity (optional - for queued instructions)
   */
  async reserveLiquidity(
    memberId: string,
    accountId: string,
    amount: string,
    currency: string,
    reservationId: string
  ): Promise<boolean> {
    // Future work: persist reservation (e.g. Redis or DB) to prevent double-spend; TTL for expiry
    logger.info('Liquidity reservation', {
      memberId,
      accountId,
      amount,
      reservationId,
    });

    return true;
  }

  /**
   * Release liquidity reservation
   */
  async releaseLiquidity(reservationId: string): Promise<void> {
    // Future work: remove reservation record from store (Redis/DB)
    logger.info('Liquidity reservation released', { reservationId });
  }
}

export const liquidityLimitsService = new LiquidityLimitsService();
