import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.api.Test;

class ShippingRateTest {
    private static final Money FIVE = Money.of(500, "PEN");
    private static final Money THREE = Money.of(300, "PEN");

    @Test
    void flatRateIgnoresTheParcel() {
        ShippingRate rate = new FlatRate(Money.of(1000, "PEN"));
        assertEquals(Money.of(1000, "PEN"), rate.cost(new Parcel(100, FIVE)));
        assertEquals(Money.of(1000, "PEN"), rate.cost(new Parcel(9000, FIVE)));
    }

    @Test
    void byWeightCountsEveryStartedKilo() {
        ShippingRate rate = new ByWeight(FIVE, THREE);
        assertEquals(Money.of(800, "PEN"), rate.cost(new Parcel(1000, FIVE)));
        assertEquals(Money.of(1100, "PEN"), rate.cost(new Parcel(1001, FIVE)));
    }

    @Test
    void freeAboveDelegatesBelowTheThreshold() {
        ShippingRate rate = new FreeAbove(Money.of(15000, "PEN"), new FlatRate(FIVE));
        assertEquals(FIVE, rate.cost(new Parcel(500, Money.of(14999, "PEN"))));
        assertEquals(Money.zero(), rate.cost(new Parcel(500, Money.of(15000, "PEN"))));
    }

    @Test
    void checkoutUsesTheCurrentStrategy() {
        Parcel parcel = new Parcel(2500, Money.of(4000, "PEN"));
        Checkout checkout = new Checkout(new ByWeight(FIVE, THREE));
        assertEquals(Money.of(5400, "PEN"), checkout.total(parcel));
        checkout.setRate(p -> Money.zero());
        assertEquals(Money.of(4000, "PEN"), checkout.total(parcel));
    }

    @Test
    void strategiesAgreeWithTheOldSwitch() {
        Parcel parcel = new Parcel(3200, Money.of(9000, "PEN"));
        ShippingRate byWeight = new ByWeight(FIVE, THREE);
        assertEquals(ShippingSwitch.cost("weight", parcel), byWeight.cost(parcel));
    }
}
