package com.bookshop.solid.dip;

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

import com.bookshop.domain.Book;
import com.bookshop.domain.Customer;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

@DisplayName("DIP -- business logic tested with fakes because it depends on abstractions")
class OrderServiceDipTest {

    private final Customer alice = new Customer("c-1", "Alice", "alice@example.com", 2);
    private final List<Book> basket = List.of(
            new Book("978-0132350884", "Clean Code", "Robert C. Martin", new BigDecimal("32.50")));

    @Test
    @DisplayName("the service runs against a fake gateway -- no credentials, no network, no mocks")
    void serviceIsTestableWithFakes() {
        List<String> chargeLog = new ArrayList<>();
        PaymentGateway fakeGateway = (customer, amount) -> {
            chargeLog.add(customer.id() + ":" + amount);
            return "fake-ref-1";
        };
        OrderService service = new OrderService(fakeGateway, new InMemoryOrderRepository());

        PlacedOrder order = service.placeOrder(alice, basket);

        assertEquals("fake-ref-1", order.paymentRef());
        assertEquals(List.of("c-1:32.50"), chargeLog);
    }

    @Test
    @DisplayName("infrastructure is swappable -- the same service works with any repository")
    void infrastructureIsSwappable() {
        OrderRepository repository = new InMemoryOrderRepository();
        OrderService service = new OrderService((customer, amount) -> "ref", repository);

        service.placeOrder(alice, basket);

        assertEquals(1, repository.forCustomer("c-1").size());
        assertEquals(new BigDecimal("32.50"), repository.forCustomer("c-1").get(0).total());
    }
}
