package calc

import (
	"math"
	"testing"
)

func TestComputeBaseFee_GKG_2025(t *testing.T) {
	tests := []struct {
		streitwert float64
		isRVG      bool
		want       float64
	}{
		// Minimum fee: first bracket, one increment
		{100, false, 40},
		{300, false, 40},
		// First bracket boundary: includes additional step for 300-500 range
		{500, false, 80},
		{501, false, 101},   // enters second bracket: 80 + 21
		{1000, false, 101},  // still one step in second bracket
		{2000, false, 143},  // 80 + 3*21 = 143
		// RVG base for 1M EUR
		{1000000, true, 5553.5},
		// GKG base for 1M EUR
		{1000000, false, 6278},
	}

	for _, tt := range tests {
		got, err := ComputeBaseFee(tt.streitwert, tt.isRVG, "2025")
		if err != nil {
			t.Fatalf("ComputeBaseFee(%v, %v, 2025): %v", tt.streitwert, tt.isRVG, err)
		}
		if math.Abs(got-tt.want) > 0.01 {
			t.Errorf("ComputeBaseFee(%v, isRVG=%v, 2025) = %v, want %v", tt.streitwert, tt.isRVG, got, tt.want)
		}
	}
}

func TestComputeBaseFee_CapsAt30M(t *testing.T) {
	// §34 GKG / §22(2) RVG: above 30M Streitwert the fee is fixed at the
	// 30M-row value. Verify cap holds for both GKG and RVG, across all
	// known fee versions.
	versions := []string{"2025", "2021", "2013", "2005"}
	for _, v := range versions {
		for _, isRVG := range []bool{false, true} {
			fee30M, err := ComputeBaseFee(30_000_000, isRVG, v)
			if err != nil {
				t.Fatalf("ComputeBaseFee(30M, %v, %s): %v", isRVG, v, err)
			}
			fee100M, err := ComputeBaseFee(100_000_000, isRVG, v)
			if err != nil {
				t.Fatalf("ComputeBaseFee(100M, %v, %s): %v", isRVG, v, err)
			}
			fee1B, err := ComputeBaseFee(1_000_000_000, isRVG, v)
			if err != nil {
				t.Fatalf("ComputeBaseFee(1B, %v, %s): %v", isRVG, v, err)
			}
			if fee100M != fee30M {
				t.Errorf("version=%s isRVG=%v: fee at 100M (%.2f) must equal fee at 30M (%.2f) — cap not applied", v, isRVG, fee100M, fee30M)
			}
			if fee1B != fee30M {
				t.Errorf("version=%s isRVG=%v: fee at 1B (%.2f) must equal fee at 30M (%.2f) — cap not applied", v, isRVG, fee1B, fee30M)
			}
		}
	}
}

func TestComputeBaseFee_BelowCapUnaffected(t *testing.T) {
	// Streitwert < 30M must continue to scale exactly as before.
	// Values are chosen comfortably below 30M — note the 500K+ bracket has
	// a 50,000-EUR step, so values within the same step ceil identically.
	values := []float64{100_000, 1_000_000, 5_000_000, 25_000_000}
	for _, sw := range values {
		feeBelow, err := ComputeBaseFee(sw, false, "2025")
		if err != nil {
			t.Fatalf("ComputeBaseFee(%v): %v", sw, err)
		}
		fee30M, err := ComputeBaseFee(30_000_000, false, "2025")
		if err != nil {
			t.Fatal(err)
		}
		if feeBelow >= fee30M {
			t.Errorf("fee at %v (%.2f) should be < fee at 30M (%.2f) — cap leaking below threshold", sw, feeBelow, fee30M)
		}
	}
}

func TestComputeUPCInstance_NotCappedByGermanLimit(t *testing.T) {
	// UPC has explicit value-based tiers up to 50M and an unlimited bracket.
	// The §34 GKG cap must not bleed into UPC fee computation.
	input := InstanceInput{Enabled: true, FeeVersion: "2026"}
	r30M, err := ComputeUPCInstance(30_000_000, input, "UPC_FIRST")
	if err != nil {
		t.Fatal(err)
	}
	r50M, err := ComputeUPCInstance(50_000_000, input, "UPC_FIRST")
	if err != nil {
		t.Fatal(err)
	}
	if r50M.ValueBasedFee <= r30M.ValueBasedFee {
		t.Errorf("UPC fee must keep scaling above 30M: 30M=%v 50M=%v", r30M.ValueBasedFee, r50M.ValueBasedFee)
	}
}

func TestComputeBaseFee_Aktuell_Alias(t *testing.T) {
	v2025, err := ComputeBaseFee(1000000, false, "2025")
	if err != nil {
		t.Fatal(err)
	}
	vAktuell, err := ComputeBaseFee(1000000, false, "Aktuell")
	if err != nil {
		t.Fatal(err)
	}
	if v2025 != vAktuell {
		t.Errorf("Aktuell alias: got %v, want %v (same as 2025)", vAktuell, v2025)
	}
}

func TestComputeBaseFee_UnknownVersion(t *testing.T) {
	_, err := ComputeBaseFee(1000, false, "1999")
	if err == nil {
		t.Error("expected error for unknown version, got nil")
	}
}

func TestComputeDEInstance_LG(t *testing.T) {
	input := InstanceInput{
		Enabled:            true,
		FeeVersion:         "2025",
		NumAttorneys:       1,
		NumPatentAttorneys: 1,
		NumClients:         1,
		OralHearing:        true,
	}
	meta := DEInfringementInstances[0] // LG
	result, err := ComputeDEInstance(1000000, input, meta, 0.19)
	if err != nil {
		t.Fatal(err)
	}

	if !result.Enabled {
		t.Fatal("expected enabled=true")
	}
	if result.CourtFeeBasis != "GKG" {
		t.Errorf("expected GKG, got %s", result.CourtFeeBasis)
	}
	// Court fee: 3.0 × 6278 = 18834
	if math.Abs(result.CourtFee-18834) > 0.01 {
		t.Errorf("CourtFee = %v, want 18834", result.CourtFee)
	}
	if result.Attorney == nil {
		t.Fatal("expected attorney breakdown")
	}
	if result.PatentAttorney == nil {
		t.Fatal("expected patent attorney breakdown")
	}
	if result.InstanceTotal <= 0 {
		t.Error("expected positive instance total")
	}
}

func TestComputeDEInstance_Disabled(t *testing.T) {
	input := InstanceInput{Enabled: false}
	meta := DEInfringementInstances[0]
	result, err := ComputeDEInstance(1000000, input, meta, 0.19)
	if err != nil {
		t.Fatal(err)
	}
	if result.Enabled {
		t.Error("expected enabled=false")
	}
	if result.InstanceTotal != 0 {
		t.Errorf("expected 0 total for disabled, got %v", result.InstanceTotal)
	}
}

func TestComputeUPCInstance_Pre2026(t *testing.T) {
	input := InstanceInput{
		Enabled:    true,
		FeeVersion: "pre2026",
		IsSME:      false,
	}
	result, err := ComputeUPCInstance(1000000, input, "UPC_FIRST")
	if err != nil {
		t.Fatal(err)
	}

	// Fixed: 11000, value-based for 1M: 4000
	if result.FixedFee != 11000 {
		t.Errorf("FixedFee = %v, want 11000", result.FixedFee)
	}
	if result.ValueBasedFee != 4000 {
		t.Errorf("ValueBasedFee = %v, want 4000", result.ValueBasedFee)
	}
	if result.CourtFeesTotal != 15000 {
		t.Errorf("CourtFeesTotal = %v, want 15000", result.CourtFeesTotal)
	}
	// Recoverable for 1M: 112000
	if result.RecoverableCeiling != 112000 {
		t.Errorf("RecoverableCeiling = %v, want 112000", result.RecoverableCeiling)
	}
}

func TestComputeUPCInstance_SME(t *testing.T) {
	input := InstanceInput{
		Enabled:    true,
		FeeVersion: "pre2026",
		IsSME:      true,
	}
	result, err := ComputeUPCInstance(1000000, input, "UPC_FIRST")
	if err != nil {
		t.Fatal(err)
	}

	// SME: 15000 × (1 - 0.4) = 9000
	if result.CourtFeesSME != 9000 {
		t.Errorf("CourtFeesSME = %v, want 9000", result.CourtFeesSME)
	}
	// InstanceTotal is the user's own outlay — court fee only, never the
	// opposing side's R.152 recoverable cap (which stays on RecoverableCeiling).
	expectedTotal := 9000.0
	if math.Abs(result.InstanceTotal-expectedTotal) > 0.01 {
		t.Errorf("InstanceTotal = %v, want %v", result.InstanceTotal, expectedTotal)
	}
	if result.RecoverableCeiling != 112000 {
		t.Errorf("RecoverableCeiling = %v, want 112000 (separate line item)", result.RecoverableCeiling)
	}
}

func TestComputeEPAInstance(t *testing.T) {
	input := InstanceInput{Enabled: true}
	result, err := ComputeEPAInstance(input, "EPA_OPPOSITION")
	if err != nil {
		t.Fatal(err)
	}
	if result.Fee != 880 {
		t.Errorf("EPA Opposition Fee = %v, want 880", result.Fee)
	}
}

func TestComputeEPAInstance_SME(t *testing.T) {
	input := InstanceInput{Enabled: true, IsSME: true}
	result, err := ComputeEPAInstance(input, "EPA_APPEAL")
	if err != nil {
		t.Fatal(err)
	}
	if result.Fee != 2015 {
		t.Errorf("EPA Appeal SME Fee = %v, want 2015", result.Fee)
	}
}

func TestCalculate_FullRequest(t *testing.T) {
	req := CostRequest{
		Streitwert: 1000000,
		VATRate:    0.19,
		Instances: map[string]InstanceInput{
			"LG": {
				Enabled:            true,
				FeeVersion:         "Aktuell",
				NumAttorneys:       1,
				NumPatentAttorneys: 1,
				NumClients:         1,
				OralHearing:        true,
			},
			"UPC_FIRST": {
				Enabled:    true,
				FeeVersion: "2026",
			},
			"EPA_OPPOSITION": {
				Enabled: true,
			},
		},
	}

	resp, err := Calculate(req)
	if err != nil {
		t.Fatal(err)
	}

	// Should have 6 DE results, 2 UPC results, 2 EPA results
	if len(resp.DEResults) != 6 {
		t.Errorf("expected 6 DE results, got %d", len(resp.DEResults))
	}
	if len(resp.UPCResults) != 2 {
		t.Errorf("expected 2 UPC results, got %d", len(resp.UPCResults))
	}
	if len(resp.EPAResults) != 2 {
		t.Errorf("expected 2 EPA results, got %d", len(resp.EPAResults))
	}

	// LG should be enabled
	if !resp.DEResults[0].Enabled {
		t.Error("LG should be enabled")
	}
	// OLG should be disabled
	if resp.DEResults[1].Enabled {
		t.Error("OLG should be disabled")
	}

	// Grand total should be positive
	if resp.Totals.GrandTotal <= 0 {
		t.Error("expected positive grand total")
	}

	// EPA fees should include opposition
	if resp.Totals.EPAFees != 880 {
		t.Errorf("EPA fees = %v, want 880", resp.Totals.EPAFees)
	}
}

func TestAttorneyFees_MultipleClients(t *testing.T) {
	input := InstanceInput{
		Enabled:      true,
		FeeVersion:   "2025",
		NumAttorneys: 1,
		NumClients:   3,
		OralHearing:  true,
	}
	meta := DEInfringementInstances[0] // LG

	result, err := ComputeDEInstance(1000000, input, meta, 0.19)
	if err != nil {
		t.Fatal(err)
	}

	// Erhöhung: min((3-1)*0.3, 2.0) × baseFee = 0.6 × 5553.5 = 3332.1
	if result.Attorney == nil {
		t.Fatal("expected attorney breakdown")
	}
	if math.Abs(result.Attorney.Erhoehungsgebuehr-3332.1) > 0.01 {
		t.Errorf("Erhoehungsgebuehr = %v, want 3332.1", result.Attorney.Erhoehungsgebuehr)
	}
}
