#include <iostream>
#include <vector>
#include <memory>

#include <json-c/json.h>

#include <plugin.h>
#include <conf.h>
#include <i18n.h>

#include "social.h"
#include "facebook.h"
#include "instagram.h"

namespace blogi {

    class Social : public PluginApi {
    public:
        const std::string getName() override { return "social"; }
        const std::string getVersion() override { return "0.1"; }
        const std::string getAuthor() override { return "Jan Koester"; }

        bool haveSettings() override { return true; }

        void initPlugin() override {
            registerGPO("d40c0dc2-9e4e-4b9b-9666-95fe84b82112",
                        "Blogi: Social Settings",
                        "Controls access to social sharing settings",
                        true);

            _backends.push_back(std::make_unique<social::Facebook>(Args));
            _backends.push_back(std::make_unique<social::Instagram>(Args));
        }

        json_object* Settings(const int tid, libhttppp::HttpRequest &req, const std::string &sessionid) override {
            std::string _lang = getLang(*Args->database[tid]);
            bool saved = false;

            // Handle POST
            libhttppp::HttpForm form;
            form.parse(req);
            for(const auto &cur : form.urlData()){
                if(cur.key == "fb_access_token"){
                    setConfig(*Args->database[tid], "SOCIAL_FB_ACCESS_TOKEN", cur.value);
                    saved = true;
                } else if(cur.key == "fb_page_id"){
                    setConfig(*Args->database[tid], "SOCIAL_FB_PAGE_ID", cur.value);
                    saved = true;
                } else if(cur.key == "ig_access_token"){
                    setConfig(*Args->database[tid], "SOCIAL_IG_ACCESS_TOKEN", cur.value);
                    saved = true;
                } else if(cur.key == "ig_user_id"){
                    setConfig(*Args->database[tid], "SOCIAL_IG_USER_ID", cur.value);
                    saved = true;
                }
            }

            json_object *jroot = json_object_new_object();
            json_object_object_add(jroot, "title", json_object_new_string("Social Sharing"));

            if(saved){
                json_object_object_add(jroot, "message", json_object_new_string("Saved!"));
                json_object_object_add(jroot, "message_type", json_object_new_string("success"));
            }

            json_object *jform = json_object_new_object();
            json_object_object_add(jform, "method", json_object_new_string("POST"));
            json_object_object_add(jform, "action", json_object_new_string(req.getRequestURL().c_str()));

            json_object *jtabs = json_object_new_array();

            // Facebook tab
            {
                json_object *jtab = json_object_new_object();
                json_object_object_add(jtab, "label", json_object_new_string("Facebook"));
                json_object *jfields = json_object_new_array();

                std::string fbToken, fbPageId;
                try { getConfig(*Args->database[tid], "SOCIAL_FB_ACCESS_TOKEN", fbToken); } catch(...) {}
                try { getConfig(*Args->database[tid], "SOCIAL_FB_PAGE_ID", fbPageId); } catch(...) {}

                json_object *jf1 = json_object_new_object();
                json_object_object_add(jf1, "name", json_object_new_string("fb_page_id"));
                json_object_object_add(jf1, "type", json_object_new_string("text"));
                json_object_object_add(jf1, "label", json_object_new_string("Facebook Page ID"));
                json_object_object_add(jf1, "value", json_object_new_string(fbPageId.c_str()));
                json_object_array_add(jfields, jf1);

                json_object *jf2 = json_object_new_object();
                json_object_object_add(jf2, "name", json_object_new_string("fb_access_token"));
                json_object_object_add(jf2, "type", json_object_new_string("password"));
                json_object_object_add(jf2, "label", json_object_new_string("Facebook Page Access Token"));
                json_object_object_add(jf2, "value", json_object_new_string(fbToken.c_str()));
                json_object_array_add(jfields, jf2);

                json_object_object_add(jtab, "fields", jfields);
                json_object_array_add(jtabs, jtab);
            }

            // Instagram tab
            {
                json_object *jtab = json_object_new_object();
                json_object_object_add(jtab, "label", json_object_new_string("Instagram"));
                json_object *jfields = json_object_new_array();

                std::string igToken, igUserId;
                try { getConfig(*Args->database[tid], "SOCIAL_IG_ACCESS_TOKEN", igToken); } catch(...) {}
                try { getConfig(*Args->database[tid], "SOCIAL_IG_USER_ID", igUserId); } catch(...) {}

                json_object *jf1 = json_object_new_object();
                json_object_object_add(jf1, "name", json_object_new_string("ig_user_id"));
                json_object_object_add(jf1, "type", json_object_new_string("text"));
                json_object_object_add(jf1, "label", json_object_new_string("Instagram User ID"));
                json_object_object_add(jf1, "value", json_object_new_string(igUserId.c_str()));
                json_object_array_add(jfields, jf1);

                json_object *jf2 = json_object_new_object();
                json_object_object_add(jf2, "name", json_object_new_string("ig_access_token"));
                json_object_object_add(jf2, "type", json_object_new_string("password"));
                json_object_object_add(jf2, "label", json_object_new_string("Instagram Access Token"));
                json_object_object_add(jf2, "value", json_object_new_string(igToken.c_str()));
                json_object_array_add(jfields, jf2);

                json_object_object_add(jtab, "fields", jfields);
                json_object_array_add(jtabs, jtab);
            }

            json_object_object_add(jform, "tabs", jtabs);
            json_object_object_add(jform, "submit", json_object_new_string("Save"));
            json_object_object_add(jroot, "form", jform);

            return jroot;
        }

        void sharePost(const int tid, SharePostType type, const std::string &url,
                       const std::string &title, const std::string &description) override {
            for(auto &backend : _backends){
                if(backend->supports(type)){
                    try {
                        backend->share(tid, type, url, title, description);
                    } catch(std::exception &e){
                        std::cerr << "[social/" << backend->name() << "] share failed: " << e.what() << std::endl;
                    }
                }
            }
        }

    private:
        std::vector<std::unique_ptr<social::SocialBackend>> _backends;
    };

};

EXPORT blogi::PluginApi* create() {
    return new blogi::Social();
}

EXPORT void destroy(blogi::PluginApi* p) {
    delete p;
}

