// C++17 teaching engine: not an Excel/Polaris API and not a distributed OT/CRDT algorithm.
#include <cassert>
#include <iostream>
#include <map>
#include <string>
#include <vector>
struct Cell { int value; bool formula; };
struct Command { std::string address; int value; };
class Sheet {
    using Cells = std::map<std::string,Cell>;
    struct History { Cells before, after; };
    Cells cells{{"A1",{1,false}},{"A2",{2,false}},{"B1",{3,true}}};
    std::vector<History> undo, redo;
    int historyRevision = 1;
public:
    int revision = 1;
    int at(const std::string& key) const { return cells.at(key).value; }
    bool apply(int expected, const std::vector<Command>& commands) {
        if (expected != revision || commands.empty()) return false;
        auto after = cells; // Stage every edit before making anything visible.
        std::map<std::string,bool> seen;
        for (const auto& command : commands) {
            auto it = after.find(command.address);
            if (it == after.end() || it->second.formula || seen[command.address]) return false;
            seen[command.address] = true;
            it->second.value = command.value;
        }
        // The host must serialize this entire method on its document thread.
        if (historyRevision != revision) undo.clear();
        undo.push_back({cells,after}); redo.clear(); cells = after;
        historyRevision = ++revision; return true;
    }
    bool undoOnce() {
        if (undo.empty() || revision != historyRevision) return false;
        auto h = undo.back(); undo.pop_back(); cells = h.before; redo.push_back(h);
        historyRevision = ++revision; return true;
    }
    bool redoOnce() {
        if (redo.empty() || revision != historyRevision) return false;
        auto h = redo.back(); redo.pop_back(); cells = h.after; undo.push_back(h);
        historyRevision = ++revision; return true;
    }
    void remoteEdit(const std::string& key, int value) {
        cells.at(key).value = value; ++revision;
        // Conservative policy: invalidate local history rather than erase another editor's work.
        undo.clear(); redo.clear(); historyRevision = revision;
    }
};
int main() {
    Sheet sheet;
    assert(!sheet.apply(1, {{"A1",10},{"A2",20},{"B1",30}}));
    assert(sheet.at("A1")==1 && sheet.at("A2")==2 && sheet.revision==1);
    assert(!sheet.undoOnce()); // Failed transaction creates no history.
    assert(!sheet.apply(1, {{"A1",10},{"A1",20}}));
    assert(!sheet.apply(1, {{"Z99",10}}));
    assert(sheet.apply(1, {{"A1",10},{"A2",20}}));
    assert(!sheet.apply(1, {{"A1",90}})); // Stale proposal.
    assert(sheet.undoOnce() && sheet.at("A1")==1 && sheet.at("A2")==2);
    assert(sheet.redoOnce() && sheet.at("A1")==10 && sheet.at("A2")==20);
    sheet.remoteEdit("A1",99);
    assert(!sheet.undoOnce() && sheet.at("A1")==99);
    std::cout << "PASS: atomic failure, formula/range/duplicate guards, revision, Undo/Redo, remote edit\n";
}
