#include <functional>
#include <iostream>
#include <map>
#include <string>
#include <vector>

// 一个“按钮”：被点击时调用事先设置好的回调。网络库里的 Channel 就是这个思路
class Button {
public:
    using Callback = std::function<void(int)>;
    void setOnClick(Callback cb) { onClick_ = std::move(cb); }
    void click(int times) {
        if (onClick_) onClick_(times);
    }

private:
    Callback onClick_;
};

int add(int a, int b) { return a + b; }

int main() {
    // 1. 最简单的 lambda：[捕获](参数) { 函数体 }
    auto square = [](int x) { return x * x; };
    std::cout << "square(5) = " << square(5) << std::endl;

    // 2. 按值捕获 [=] 和按引用捕获 [&]
    int count = 0;
    auto byValue = [count]() { return count + 1; };  // 拷了一份 count，之后外面怎么改都不影响
    auto byRef = [&count]() { ++count; };            // 引用外面的 count，能修改它
    byRef();
    byRef();
    std::cout << "count = " << count << ", byValue() = " << byValue() << std::endl;

    // 3. std::function 能装下任何“可调用的东西”：普通函数、lambda
    std::function<int(int, int)> op = add;
    std::cout << "op(2, 3) = " << op(2, 3) << std::endl;
    op = [](int a, int b) { return a * b; };
    std::cout << "op(2, 3) = " << op(2, 3) << std::endl;

    // 4. 回调：把“发生某事时做什么”交给别人保存，事件发生时由别人来调用
    Button button;
    int total = 0;
    button.setOnClick([&total](int times) {
        total += times;
        std::cout << "clicked " << times << " times, total " << total << std::endl;
    });
    button.click(1);
    button.click(3);

    // 5. 用 map 存“命令名 -> 处理函数”，这就是阶段 2 命令分发的雏形
    std::map<std::string, std::function<std::string(const std::string&)>> commands;
    commands["PING"] = [](const std::string&) { return std::string("PONG"); };
    commands["ECHO"] = [](const std::string& arg) { return arg; };
    for (std::string name : {"PING", "ECHO", "GET"}) {
        auto it = commands.find(name);
        if (it == commands.end()) {
            std::cout << name << " -> ERR unknown command" << std::endl;
        } else {
            std::cout << name << " -> " << it->second("hello") << std::endl;
        }
    }
    return 0;
}
