package com.bookshop.behavioral.observer;

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

import com.bookshop.domain.Book;
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("Observer -- inventory announces restocks without knowing who is listening")
class InventoryObserverTest {

    private final Inventory inventory = new Inventory();
    private final Book book = new Book("978-0201633610", "Design Patterns",
            "Gamma, Helm, Johnson, Vlissides", new BigDecimal("42.00"));

    @Test
    @DisplayName("every subscriber hears about a restock -- email and lambda alike")
    void allSubscribersAreNotified() {
        EmailAlerts email = new EmailAlerts();
        List<String> smsLog = new ArrayList<>();
        inventory.subscribe(email);
        inventory.subscribe(b -> smsLog.add("SMS: " + b.title() + " available"));

        inventory.restock(book);

        assertEquals(List.of("To waitlist: \"Design Patterns\" is back in stock!"), email.outbox());
        assertEquals(List.of("SMS: Design Patterns available"), smsLog);
    }

    @Test
    @DisplayName("unsubscribed listeners stop receiving events")
    void unsubscribeStopsNotifications() {
        EmailAlerts email = new EmailAlerts();
        inventory.subscribe(email);

        inventory.unsubscribe(email);
        inventory.restock(book);

        assertTrue(email.outbox().isEmpty());
    }

    @Test
    @DisplayName("the subject needs no changes to support a brand-new reaction")
    void newReactionsAreJustNewSubscribers() {
        List<String> dashboardEvents = new ArrayList<>();
        inventory.subscribe(b -> dashboardEvents.add(b.isbn()));

        inventory.restock(book);

        assertEquals(List.of("978-0201633610"), dashboardEvents);
    }
}
