#include "json.hpp"
#include <string>

#include <fstream>
#include <iostream>

using json = nlohmann::json;

class BinaryDecisionTree {
public:
    std::string question;
    BinaryDecisionTree *left;
    BinaryDecisionTree *right;
    BinaryDecisionTree(std::string qstn) : question(qstn), left(nullptr), right(nullptr) {}
    BinaryDecisionTree(std::string qstn, BinaryDecisionTree *lft, BinaryDecisionTree* rgt) : question(qstn), left(lft), right(rgt) {}
};

BinaryDecisionTree* ask(BinaryDecisionTree *current)
{
    std::string answer;

    std::cout << current->question << std::endl;
    std::cout << "[yes / no]" << std::endl;
    while (true) {
        std::getline (std::cin, answer);
        if (answer == "yes") {
            if (current->left) {
                return current->left;
            } else {
                std::cout << "Great!" << std::endl;
                return nullptr;
            }
        } else if (answer == "no") {
            if (current->right) {
                return current->right;
            } else {
                std::cout << "What were you thinking of?" << std::endl;
                answer = "";
                while (answer == "") {
                    std::getline (std::cin, answer);
                }
                BinaryDecisionTree *leaf = new BinaryDecisionTree("Are you thinking of '" + answer + "'?");
                std::cout << "What is a question I can ask you that is true if you are thinking of '" << answer << "'?" << std::endl;
                answer = "";
                while (answer == "") {
                    std::getline (std::cin, answer);
                }
                BinaryDecisionTree *question = new BinaryDecisionTree(answer, leaf, nullptr);
                current->right = question;
                return nullptr;
            }
        } else {
            std::cout << "yes or no!" << std::endl;
        }
    }
}

BinaryDecisionTree* parse(json j)
{
    if (j.is_null()) return nullptr;
    BinaryDecisionTree *tree = new BinaryDecisionTree(j["question"].get<std::string>());
    tree->left = parse(j["left"]);
    tree->right = parse(j["right"]);
    return tree;
}

BinaryDecisionTree* read_file(char *path)
{
    std::ifstream i(path);
    json j;
    i >> j;
    return parse(j);
}

int main(int argc, char **argv)
{
    if (argc != 2) {
        std::cout << "Must specify file!" << std::endl;
        return -1;
    }

    BinaryDecisionTree *root = read_file(argv[1]);
    BinaryDecisionTree *curr = root;

    while (true) {
        // After these lines, curr will point at the current node,
        // and prev will point at the previous node (the parent of curr).
        BinaryDecisionTree *prev = curr;
        curr = ask(curr);
        if (curr == nullptr) {
            std::string answer;
            std::cout << "Do you want to play again?" << std::endl;
            std::cout << "[yes / no]" << std::endl;
            while (true) {
                std::getline (std::cin, answer);
                if (answer == "no") {
                    std::cout << "Thanks for playing!" << std::endl;
                    return 0;
                } else if (answer == "yes") {
                    curr = root;
                    break;
                }
            }
        }
    }
}

