package trading

import (
	"testing"

	"git.toki-labs.com/toki/alt/packages/domain/market"
)

func krwPolicy(maxNotional string) RiskPolicy {
	return RiskPolicy{
		MaxOrderNotionalByCurrency: map[market.Currency]market.Decimal{
			market.CurrencyKRW: {Value: maxNotional},
		},
		MaxDailyOrders:    5,
		MaxOpenOrders:     3,
		AllowShortSelling: false,
	}
}

func buyIntent(qty, limitPrice string) OrderIntent {
	return OrderIntent{
		InstrumentID: "KRX:005930",
		Side:         OrderSideBuy,
		Quantity:     market.Quantity{Amount: market.Decimal{Value: qty}},
		Type:         OrderTypeLimit,
		LimitPrice: market.Price{
			Currency: market.CurrencyKRW,
			Amount:   market.Decimal{Value: limitPrice},
		},
	}
}

func TestEvaluateRiskKillSwitchHaltedBlocks(t *testing.T) {
	ks := KillSwitchState{Halted: true, Reason: "manual halt"}
	dec := EvaluateRisk(RiskPolicy{}, ks, buyIntent("1", "75000"), RiskUsage{})
	if dec.Allowed {
		t.Error("expected risk denied when kill switch is halted")
	}
	if dec.Reason != "manual halt" {
		t.Errorf("unexpected reason %q", dec.Reason)
	}
}

func TestEvaluateRiskKillSwitchDefaultReasonFallback(t *testing.T) {
	ks := KillSwitchState{Halted: true, Reason: ""}
	dec := EvaluateRisk(RiskPolicy{}, ks, buyIntent("1", "75000"), RiskUsage{})
	if dec.Allowed {
		t.Error("expected risk denied when kill switch is halted")
	}
	if dec.Reason == "" {
		t.Error("expected fallback reason, got empty string")
	}
}

func TestEvaluateRiskKillSwitchOffAllows(t *testing.T) {
	ks := KillSwitchState{Halted: false}
	policy := krwPolicy("1000000")
	dec := EvaluateRisk(policy, ks, buyIntent("1", "75000"), RiskUsage{})
	if !dec.Allowed {
		t.Errorf("expected allowed, got reason %q", dec.Reason)
	}
}

func TestEvaluateRiskShortSellingBlocked(t *testing.T) {
	ks := KillSwitchState{Halted: false}
	policy := RiskPolicy{AllowShortSelling: false}
	intent := OrderIntent{
		InstrumentID: "KRX:005930",
		Side:         OrderSideSell,
		Quantity:     market.Quantity{Amount: market.Decimal{Value: "1"}},
		Type:         OrderTypeMarket,
	}
	dec := EvaluateRisk(policy, ks, intent, RiskUsage{})
	if dec.Allowed {
		t.Error("expected sell order blocked when short selling is disallowed")
	}
}

func TestEvaluateRiskShortSellingAllowed(t *testing.T) {
	ks := KillSwitchState{Halted: false}
	policy := RiskPolicy{AllowShortSelling: true}
	intent := OrderIntent{
		InstrumentID: "KRX:005930",
		Side:         OrderSideSell,
		Quantity:     market.Quantity{Amount: market.Decimal{Value: "1"}},
		Type:         OrderTypeMarket,
	}
	dec := EvaluateRisk(policy, ks, intent, RiskUsage{})
	if !dec.Allowed {
		t.Errorf("expected sell allowed when AllowShortSelling=true, got reason %q", dec.Reason)
	}
}

func TestEvaluateRiskNotionalBelowLimitAllows(t *testing.T) {
	ks := KillSwitchState{Halted: false}
	// 10 * 75000 = 750000 < 1000000
	dec := EvaluateRisk(krwPolicy("1000000"), ks, buyIntent("10", "75000"), RiskUsage{})
	if !dec.Allowed {
		t.Errorf("expected allowed, got %q", dec.Reason)
	}
}

func TestEvaluateRiskNotionalAboveLimitBlocks(t *testing.T) {
	ks := KillSwitchState{Halted: false}
	// 20 * 75000 = 1500000 > 1000000
	dec := EvaluateRisk(krwPolicy("1000000"), ks, buyIntent("20", "75000"), RiskUsage{})
	if dec.Allowed {
		t.Error("expected blocked when notional exceeds limit")
	}
}

func TestEvaluateRiskNotionalExactlyAtLimitAllows(t *testing.T) {
	ks := KillSwitchState{Halted: false}
	// 10 * 100000 = 1000000 == 1000000
	dec := EvaluateRisk(krwPolicy("1000000"), ks, buyIntent("10", "100000"), RiskUsage{})
	if !dec.Allowed {
		t.Errorf("expected allowed at exact limit, got %q", dec.Reason)
	}
}

func TestEvaluateRiskMarketOrderSkipsNotionalCheck(t *testing.T) {
	ks := KillSwitchState{Halted: false}
	policy := krwPolicy("1000000")
	// market order has no limit price, so no notional check
	intent := OrderIntent{
		InstrumentID: "KRX:005930",
		Side:         OrderSideBuy,
		Quantity:     market.Quantity{Amount: market.Decimal{Value: "9999"}},
		Type:         OrderTypeMarket,
	}
	dec := EvaluateRisk(policy, ks, intent, RiskUsage{})
	if !dec.Allowed {
		t.Errorf("expected market order allowed (no limit_price to check notional), got %q", dec.Reason)
	}
}

func TestEvaluateRiskDifferentCurrencyNotionalUnchecked(t *testing.T) {
	ks := KillSwitchState{Halted: false}
	// policy only sets KRW limit; USD order should pass
	policy := krwPolicy("1000000")
	intent := OrderIntent{
		InstrumentID: "NYSE:AAPL",
		Side:         OrderSideBuy,
		Quantity:     market.Quantity{Amount: market.Decimal{Value: "100"}},
		Type:         OrderTypeLimit,
		LimitPrice: market.Price{
			Currency: market.CurrencyUSD,
			Amount:   market.Decimal{Value: "200"},
		},
	}
	dec := EvaluateRisk(policy, ks, intent, RiskUsage{})
	if !dec.Allowed {
		t.Errorf("expected USD order allowed when only KRW limit set, got %q", dec.Reason)
	}
}

func TestEvaluateRiskMaxDailyOrdersAllowsBelowLimit(t *testing.T) {
	ks := KillSwitchState{Halted: false}
	policy := RiskPolicy{MaxDailyOrders: 5}
	// 4 orders submitted today — one more should be allowed
	dec := EvaluateRisk(policy, ks, buyIntent("1", ""), RiskUsage{DailyOrderCount: 4})
	if !dec.Allowed {
		t.Errorf("expected allowed when daily count below limit, got %q", dec.Reason)
	}
}

func TestEvaluateRiskMaxDailyOrdersBlocksAtLimit(t *testing.T) {
	ks := KillSwitchState{Halted: false}
	policy := RiskPolicy{MaxDailyOrders: 5}
	// exactly 5 orders already submitted — next must be blocked
	dec := EvaluateRisk(policy, ks, buyIntent("1", ""), RiskUsage{DailyOrderCount: 5})
	if dec.Allowed {
		t.Error("expected blocked when daily order count equals limit")
	}
}

func TestEvaluateRiskMaxDailyOrdersBlocksAboveLimit(t *testing.T) {
	ks := KillSwitchState{Halted: false}
	policy := RiskPolicy{MaxDailyOrders: 5}
	dec := EvaluateRisk(policy, ks, buyIntent("1", ""), RiskUsage{DailyOrderCount: 7})
	if dec.Allowed {
		t.Error("expected blocked when daily order count exceeds limit")
	}
}

func TestEvaluateRiskMaxDailyOrdersZeroMeansNoLimit(t *testing.T) {
	ks := KillSwitchState{Halted: false}
	policy := RiskPolicy{MaxDailyOrders: 0}
	dec := EvaluateRisk(policy, ks, buyIntent("1", ""), RiskUsage{DailyOrderCount: 999})
	if !dec.Allowed {
		t.Errorf("expected allowed when MaxDailyOrders=0 (no limit), got %q", dec.Reason)
	}
}

func TestEvaluateRiskMaxOpenOrdersAllowsBelowLimit(t *testing.T) {
	ks := KillSwitchState{Halted: false}
	policy := RiskPolicy{MaxOpenOrders: 3}
	// 2 open orders — one more should be allowed
	dec := EvaluateRisk(policy, ks, buyIntent("1", ""), RiskUsage{OpenOrderCount: 2})
	if !dec.Allowed {
		t.Errorf("expected allowed when open count below limit, got %q", dec.Reason)
	}
}

func TestEvaluateRiskMaxOpenOrdersBlocksAtLimit(t *testing.T) {
	ks := KillSwitchState{Halted: false}
	policy := RiskPolicy{MaxOpenOrders: 3}
	// exactly 3 open orders — next must be blocked
	dec := EvaluateRisk(policy, ks, buyIntent("1", ""), RiskUsage{OpenOrderCount: 3})
	if dec.Allowed {
		t.Error("expected blocked when open order count equals limit")
	}
}

func TestEvaluateRiskMaxOpenOrdersZeroMeansNoLimit(t *testing.T) {
	ks := KillSwitchState{Halted: false}
	policy := RiskPolicy{MaxOpenOrders: 0}
	dec := EvaluateRisk(policy, ks, buyIntent("1", ""), RiskUsage{OpenOrderCount: 999})
	if !dec.Allowed {
		t.Errorf("expected allowed when MaxOpenOrders=0 (no limit), got %q", dec.Reason)
	}
}

func TestDefaultKillSwitchIsHalted(t *testing.T) {
	ks := DefaultKillSwitch()
	if !ks.Halted {
		t.Error("default kill switch must be halted=true")
	}
	if ks.Reason == "" {
		t.Error("default kill switch must include a non-empty reason")
	}
}
