package cart

import (
	"encoding/json"
	"testing"
)

func TestPriceMarshalJSON(t *testing.T) {
	p := Price{IncVat: 13700, VatRates: map[float32]int64{25: 2500, 12: 1200}}
	// ExVat = 13700 - (2500+1200) = 10000
	data, err := json.Marshal(p)
	if err != nil {
		t.Fatalf("marshal error: %v", err)
	}
	// Unmarshal into a generic struct to validate fields
	var out struct {
		ExVat  int64            `json:"exVat"`
		IncVat int64            `json:"incVat"`
		Vat    map[string]int64 `json:"vat"`
	}
	if err := json.Unmarshal(data, &out); err != nil {
		t.Fatalf("unmarshal error: %v", err)
	}
	if out.ExVat != 10000 {
		t.Fatalf("expected exVat 10000 got %d", out.ExVat)
	}
	if out.IncVat != 13700 {
		t.Fatalf("expected incVat 13700 got %d", out.IncVat)
	}
	if out.Vat["25"] != 2500 || out.Vat["12"] != 1200 {
		t.Fatalf("unexpected vat map: %#v", out.Vat)
	}
}

func TestNewPriceFromIncVat(t *testing.T) {
	p := NewPriceFromIncVat(1250, 25)
	if p.IncVat != 1250 {
		t.Fatalf("expected IncVat %d got %d", 1250, p.IncVat)
	}
	if p.VatRates[25] != 250 {
		t.Fatalf("expected VAT 25 rate %d got %d", 250, p.VatRates[25])
	}
	if p.ValueExVat() != 1000 {
		t.Fatalf("expected exVat %d got %d", 750, p.ValueExVat())
	}
}

func TestSumPrices(t *testing.T) {
	// We'll construct prices via raw struct since constructor expects tax math.
	// IncVat already includes vat portions.
	a := Price{IncVat: 1250, VatRates: map[float32]int64{25: 250}}          // ex=1000
	b := Price{IncVat: 2740, VatRates: map[float32]int64{25: 500, 12: 240}} // ex=2000
	c := Price{IncVat: 0, VatRates: nil}

	sum := SumPrices(a, b, c)

	if sum.IncVat != 3990 { // 1250+2740
		t.Fatalf("expected incVat 3990 got %d", sum.IncVat)
	}
	if len(sum.VatRates) != 2 {
		t.Fatalf("expected 2 vat rates got %d", len(sum.VatRates))
	}
	if sum.VatRates[25] != 750 {
		t.Fatalf("expected 25%% vat 750 got %d", sum.VatRates[25])
	}
	if sum.VatRates[12] != 240 {
		t.Fatalf("expected 12%% vat 240 got %d", sum.VatRates[12])
	}
	if sum.ValueExVat() != 3000 { // 3990 - (750+240)
		t.Fatalf("expected exVat 3000 got %d", sum.ValueExVat())
	}
}

func TestSumPricesEmpty(t *testing.T) {
	sum := SumPrices()
	if sum.IncVat != 0 || sum.VatRates == nil { // constructor sets empty map
		t.Fatalf("expected zero price got %#v", sum)
	}
}

func TestMultiplyPriceFunction(t *testing.T) {
	base := Price{IncVat: 1250, VatRates: map[float32]int64{25: 250}}
	multiplied := MultiplyPrice(base, 3)
	if multiplied.IncVat != 1250*3 {
		t.Fatalf("expected IncVat %d got %d", 1250*3, multiplied.IncVat)
	}
	if multiplied.VatRates[25] != 250*3 {
		t.Fatalf("expected VAT 25 rate %d got %d", 250*3, multiplied.VatRates[25])
	}
	if multiplied.ValueExVat() != (1250-250)*3 {
		t.Fatalf("expected exVat %d got %d", (1250-250)*3, multiplied.ValueExVat())
	}
}

func TestPriceAddSubtract(t *testing.T) {
	a := Price{IncVat: 1000, VatRates: map[float32]int64{25: 200}}
	b := Price{IncVat: 500, VatRates: map[float32]int64{25: 100, 12: 54}}

	acc := NewPrice()
	acc.Add(a)
	acc.Add(b)

	if acc.IncVat != 1500 {
		t.Fatalf("expected IncVat 1500 got %d", acc.IncVat)
	}
	if acc.VatRates[25] != 300 || acc.VatRates[12] != 54 {
		t.Fatalf("unexpected VAT map: %#v", acc.VatRates)
	}

	// Subtract b then a returns to zero
	acc.Subtract(b)
	acc.Subtract(a)
	if acc.IncVat != 0 {
		t.Fatalf("expected IncVat 0 got %d", acc.IncVat)
	}
	if len(acc.VatRates) != 2 || acc.VatRates[25] != 0 || acc.VatRates[12] != 0 {
		t.Fatalf("expected zeroed vat rates got %#v", acc.VatRates)
	}
}

func TestPriceMultiplyMethod(t *testing.T) {
	p := Price{IncVat: 2000, VatRates: map[float32]int64{25: 400}}
	// Value before multiply
	exBefore := p.ValueExVat()
	p.Multiply(2)
	if p.IncVat != 4000 {
		t.Fatalf("expected IncVat 4000 got %d", p.IncVat)
	}
	if p.VatRates[25] != 800 {
		t.Fatalf("expected VAT 800 got %d", p.VatRates[25])
	}
	if p.ValueExVat() != exBefore*2 {
		t.Fatalf("expected exVat %d got %d", exBefore*2, p.ValueExVat())
	}
}
