#include "ui.hpp"
#include "database.hpp"
#include <iostream>

void sync_map_to_list(const std::map<int, Critter> &critters, std::vector<CritterEntry> &critter_list) {
    critter_list.clear();
    for (const auto &[id, critter] : critters) {
        critter_list.push_back({id, critter});
    }
}

bool setup_data_binding(Rml::Context *context, Rml::DataModelHandle &model_handle, AppData &app_data, std::vector<CritterEntry> &critter_list, std::map<int, Critter> &critters) {
    Rml::DataModelConstructor dmc = context->CreateDataModel("app_data");
    if (!dmc) {
        std::cout << "[ERROR] Could not create 'app_data' data binding.\n";
        return false;
    }

    if (auto handle = dmc.RegisterStruct<Critter>()) {
        handle.RegisterMember("id", &Critter::id);
        handle.RegisterMember("name", &Critter::name);
        handle.RegisterMember("gender", &Critter::gender);
        handle.RegisterMember("species", &Critter::species);
        handle.RegisterMember("notes", &Critter::notes);
        handle.RegisterMember("mother_id", &Critter::mother_id);
        handle.RegisterMember("father_id", &Critter::father_id);
    }

    if (auto handle = dmc.RegisterStruct<CritterEntry>()) {
        handle.RegisterMember("key", &CritterEntry::key);
        handle.RegisterMember("value", &CritterEntry::value);
    }

    if (auto handle = dmc.RegisterStruct<NewCritterForm>()) {
        handle.RegisterMember("name", &NewCritterForm::name);
        handle.RegisterMember("gender", &NewCritterForm::gender);
        handle.RegisterMember("mother_id", &NewCritterForm::mother_id);
        handle.RegisterMember("father_id", &NewCritterForm::father_id);
        handle.RegisterMember("notes", &NewCritterForm::notes);
        handle.RegisterMember("species", &NewCritterForm::species);
    }

    dmc.RegisterArray<std::vector<CritterEntry>>();

    dmc.Bind("critters", &critter_list);
    dmc.Bind("page_title", &app_data.page_title);
    dmc.Bind("error_message", &app_data.error_message);
    
    // New Critter dialog
    dmc.Bind("is_add_critter_dialog_open", &app_data.is_add_critter_dialog_open);
    dmc.Bind("new_critter_form", &app_data.new_critter_form);

    // Confirmation dialog
    dmc.Bind("is_confirmation_dialog_open", &app_data.is_confirmation_dialog_open);
    dmc.Bind("confirmation_dialog_text", &app_data.confirmation_dialog_text);

    // Submit Add Critter
    dmc.BindEventCallback("submit_add_critter", [&app_data, &critters, &critter_list](Rml::DataModelHandle handle, Rml::Event &, const Rml::VariantList &) {
        Critter temp;
        temp.name = app_data.new_critter_form.name;
        temp.gender = app_data.new_critter_form.gender;
        temp.mother_id = app_data.new_critter_form.mother_id;
        temp.father_id = app_data.new_critter_form.father_id;
        temp.notes = app_data.new_critter_form.notes;
        temp.species = app_data.new_critter_form.species;

        std::string err;
        if (!validate_critter(temp, critters, err)) {
            app_data.error_message = err;
            handle.DirtyVariable("error_message");
            return;
        }

        int new_id = 0;
        if (db_add_critter(temp, new_id)) {
            db_get_all_critters(critters);
            sync_map_to_list(critters, critter_list);

            app_data.new_critter_form.Clear();
            app_data.error_message.clear();
            app_data.is_add_critter_dialog_open = false;

            handle.DirtyVariable("critters");
            handle.DirtyVariable("new_critter_form");
            handle.DirtyVariable("error_message");
            handle.DirtyVariable("is_add_critter_dialog_open");
        } else {
            app_data.error_message = "Failed to write to database.";
            handle.DirtyVariable("error_message");
        }
    });

    // Request Critter Deletion
    dmc.BindEventCallback("delete_critter", [&app_data, &critters, &critter_list](Rml::DataModelHandle const_handle, Rml::Event &, const Rml::VariantList &args) {
        if (args.empty()) return;

        Rml::DataModelHandle handle = const_handle;

        int target_id = args[0].Get<int>();

        app_data.confirmation_dialog_text = "Are you sure you want to delete critter '" + critters[target_id].name + "'? This action cannot be undone.";
        
        app_data.on_confirm_action = [&critters, &critter_list, target_id, const_handle]() {
            Rml::DataModelHandle handle = const_handle; 
            if (db_delete_critter(target_id)) {
                critters.erase(target_id);
                sync_map_to_list(critters, critter_list);
                handle.DirtyVariable("critters");
                std::cout << "[INFO] Deleted critter with ID #" << target_id << std::endl;
            }
        };

        app_data.is_confirmation_dialog_open = true;
        handle.DirtyVariable("confirmation_dialog_text");
        handle.DirtyVariable("is_confirmation_dialog_open");
    });

    dmc.BindEventCallback("confirm_dialog_yes", [&app_data](Rml::DataModelHandle const_handle, Rml::Event &, const Rml::VariantList &) {
        Rml::DataModelHandle handle = const_handle; 

        if (app_data.on_confirm_action) {
            app_data.on_confirm_action();
            app_data.on_confirm_action = nullptr;
        }
        app_data.is_confirmation_dialog_open = false;
        handle.DirtyVariable("is_confirmation_dialog_open");
    });

    dmc.BindEventCallback("confirm_dialog_no", [&app_data](Rml::DataModelHandle const_handle, Rml::Event &, const Rml::VariantList &) {
        Rml::DataModelHandle handle = const_handle;

        app_data.on_confirm_action = nullptr;
        app_data.is_confirmation_dialog_open = false;
        handle.DirtyVariable("is_confirmation_dialog_open");
    });

    model_handle = dmc.GetModelHandle();
    return true;
}