#include <algorithm>
#include <cassert>
#include <functional>
#include <iostream>
#include <memory>
#include <vector>

template <typename State>
struct Observer {
    virtual ~Observer() = default;
    virtual void update(State state) = 0;
};

class Browser {
public:
    enum class State {
        Closing,
        FocusChanged
    };
    using BrowserObserver = Observer<State>;

    ~Browser() {
        std::cout << "Browser is closing\n";
        notify(State::Closing);
        std::cout << "Browser closed\n";
    }
    // Rule of 5 :)

    void attach(BrowserObserver* observer) { _observers.push_back(observer); }
    void detach(BrowserObserver* observer) { std::erase(_observers, observer); }

private:
    void notify(State state) const {
        std::ranges::for_each(_observers, [state](auto* observer) {
            observer->update(state);
        });
    }

    std::vector<BrowserObserver*> _observers;
};

class TabStripManager : public Browser::BrowserObserver {
public:
    TabStripManager(Browser* browser)
        : _browser(browser) {
        assert(browser);
        browser->attach(this);
    }

    ~TabStripManager() {
        if (_browser) {
            _browser->detach(this);
        }
    }
    // Rule of 5 :)

    // dispatch message
    void update(Browser::State state) override {
        switch (state) {
        case Browser::State::Closing: {
            browserAboutToQuit();
            return;
        }
        case Browser::State::FocusChanged: {
            browserFocusChanged();
            return;
        }
        }
    }

private:
    void browserAboutToQuit() {
        std::cout << "TabStripManager will close tabs\n";
        _browser = nullptr;
    }

    void browserFocusChanged() {
        std::cout << "TabStripManager lost focus\n";
    }

    Browser* _browser;
};

int main() {
    std::unique_ptr<Browser> browser = std::make_unique<Browser>();
    TabStripManager manager(browser.get());
    browser = nullptr;
}