/**
 * Exchange reputation scoring and badge calculation.
 *
 * Score formula (0-100):
 *   completionRate × 50 + (1 - disputeRate) × 25 + (1 - disputeLossRate) × 15 + confirmSpeed × 10
 *
 * Badges:
 *   verified_seller   — 5+ completed trades, score ≥ 70
 *   liquidity_provider — has standing orders
 *   top_trader        — ≥ $10k equivalent volume
 */

import type { ExchangeReputationRecord, ExchangeReputationDoc, ExchangeTradesDoc, LiquidityPosition } from './schemas';

export const DEFAULT_REPUTATION: ExchangeReputationRecord = {
	did: '',
	tradesCompleted: 0,
	tradesCancelled: 0,
	disputesRaised: 0,
	disputesLost: 0,
	totalVolumeBase: 0,
	avgConfirmTimeMs: 0,
	score: 50,
	badges: [],
};

/**
 * Calculate reputation score from raw stats.
 */
export function calculateScore(rec: ExchangeReputationRecord): number {
	const totalTrades = rec.tradesCompleted + rec.tradesCancelled;
	if (totalTrades === 0) return 50; // neutral default

	const completionRate = rec.tradesCompleted / totalTrades;
	const totalDisputes = rec.disputesRaised;
	const disputeRate = totalTrades > 0 ? totalDisputes / totalTrades : 0;
	const disputeLossRate = totalDisputes > 0 ? rec.disputesLost / totalDisputes : 0;

	// Confirm speed: normalize to 0-1 (faster = higher).
	// Target: < 1hr = perfect, > 24hr = 0. avgConfirmTimeMs capped at 24h.
	const oneHour = 3600_000;
	const twentyFourHours = 86400_000;
	const speedScore = rec.avgConfirmTimeMs <= 0 ? 0.5
		: rec.avgConfirmTimeMs <= oneHour ? 1.0
		: Math.max(0, 1 - (rec.avgConfirmTimeMs - oneHour) / (twentyFourHours - oneHour));

	const score =
		completionRate * 50 +
		(1 - disputeRate) * 25 +
		(1 - disputeLossRate) * 15 +
		speedScore * 10;

	return Math.round(Math.max(0, Math.min(100, score)));
}

/**
 * Compute badges based on reputation stats.
 * LP badge awarded for standing orders OR active LP positions.
 */
export function computeBadges(
	rec: ExchangeReputationRecord,
	hasStandingOrders: boolean,
	hasActiveLpPositions: boolean = false,
): string[] {
	const badges: string[] = [];

	if (rec.tradesCompleted >= 5 && rec.score >= 70) {
		badges.push('verified_seller');
	}

	if (hasStandingOrders || hasActiveLpPositions) {
		badges.push('liquidity_provider');
	}

	// $10k volume threshold — base units with 6 decimals → 10_000 * 1_000_000
	if (rec.totalVolumeBase >= 10_000_000_000) {
		badges.push('top_trader');
	}

	return badges;
}

/**
 * Update reputation for a DID after a completed trade.
 */
export function updateReputationAfterTrade(
	rec: ExchangeReputationRecord,
	tokenAmount: number,
	confirmTimeMs: number,
): ExchangeReputationRecord {
	const newCompleted = rec.tradesCompleted + 1;
	const newVolume = rec.totalVolumeBase + tokenAmount;

	// Running average of confirm time
	const prevTotal = rec.avgConfirmTimeMs * rec.tradesCompleted;
	const newAvg = newCompleted > 0 ? (prevTotal + confirmTimeMs) / newCompleted : 0;

	const updated: ExchangeReputationRecord = {
		...rec,
		tradesCompleted: newCompleted,
		totalVolumeBase: newVolume,
		avgConfirmTimeMs: newAvg,
	};

	updated.score = calculateScore(updated);
	return updated;
}

/**
 * Get reputation for a DID from the doc, or return defaults.
 */
export function getReputation(did: string, doc: ExchangeReputationDoc): ExchangeReputationRecord {
	return doc.records[did] || { ...DEFAULT_REPUTATION, did };
}

/**
 * Check if a DID has standing orders in the intents doc.
 */
export function hasStandingOrders(
	did: string,
	intentsDoc: { intents: Record<string, { creatorDid: string; isStandingOrder: boolean; status: string }> },
): boolean {
	return Object.values(intentsDoc.intents).some(
		i => i.creatorDid === did && i.isStandingOrder && i.status === 'active',
	);
}

/**
 * Check if a DID has active liquidity pool positions.
 */
export function hasActiveLpPositions(
	did: string,
	poolsDoc: { positions: Record<string, LiquidityPosition> } | null | undefined,
): boolean {
	if (!poolsDoc) return false;
	return Object.values(poolsDoc.positions).some(
		p => p.creatorDid === did && p.status === 'active',
	);
}
