#include "supabase_client.h"
#include <curl/curl.h>
#include <nlohmann/json.hpp>
#include <thread>
#include <iostream>
#include <algorithm>
#include <cmath>

using json = nlohmann::json;

namespace {
// Supabase constants (publishable anon key)
const std::string SUPABASE_URL = "https://xzxpmvyamjvtxpwnjpad.supabase.co";
const std::string SUPABASE_ANON_KEY = "sb_publishable_GqQx844xYDizO9-ytlBXfA_MVT6N7yA";

std::string buildUrl(const std::string &path) {
    std::string url = SUPABASE_URL;
    if (!url.empty() && url.back() == '/') url.pop_back();
    url += "/rest/v1/" + path;
    return url;
}

size_t curlWriteCallback(void* contents, size_t size, size_t nmemb, void* userp) {
    size_t realSize = size * nmemb;
    std::string *s = reinterpret_cast<std::string*>(userp);
    s->append(reinterpret_cast<char*>(contents), realSize);
    return realSize;
}

struct CurlInit {
    CurlInit() { curl_global_init(CURL_GLOBAL_DEFAULT); }
    ~CurlInit() { curl_global_cleanup(); }
};
static CurlInit g_curl_init;
}

namespace supabase {

static bool g_verbose = false;

void SetVerbose(bool enabled) {
    g_verbose = enabled;
}


void SubmitHighscoreAsync(const ScoreEntry &entry) {
    std::thread([entry]() {
        try {
            CURL* curl = curl_easy_init();
            if (!curl) return;

            std::string url = buildUrl("highscores");

            json j;
            j["score"] = entry.score;
            j["lines"] = entry.lines;
            j["level"] = entry.level;
            j["time_sec"] = static_cast<int>(std::lround(entry.timeSec));
            j["name"] = entry.name;
            j["game_type"] = entry.gameType;
            j["timestamp"] = static_cast<int>(std::time(nullptr));

            std::string body = j.dump();
            struct curl_slist *headers = nullptr;
            std::string h1 = std::string("apikey: ") + SUPABASE_ANON_KEY;
            std::string h2 = std::string("Authorization: Bearer ") + SUPABASE_ANON_KEY;
            headers = curl_slist_append(headers, h1.c_str());
            headers = curl_slist_append(headers, h2.c_str());
            headers = curl_slist_append(headers, "Content-Type: application/json");

            std::string resp;
            curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
            curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
            curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body.c_str());
            curl_easy_setopt(curl, CURLOPT_TIMEOUT, 5L);
            curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlWriteCallback);
            curl_easy_setopt(curl, CURLOPT_WRITEDATA, &resp);

            if (g_verbose) {
                std::cerr << "[Supabase] POST " << url << "\n";
                std::cerr << "[Supabase] Body: " << body << "\n";
            }

            CURLcode res = curl_easy_perform(curl);
            if (res != CURLE_OK) {
                if (g_verbose) std::cerr << "[Supabase] POST error: " << curl_easy_strerror(res) << "\n";
            } else {
                long http_code = 0;
                curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
                if (g_verbose) {
                    std::cerr << "[Supabase] POST response code: " << http_code << " body_len=" << resp.size() << "\n";
                    if (!resp.empty()) std::cerr << "[Supabase] POST response: " << resp << "\n";
                }
            }

            curl_slist_free_all(headers);
            curl_easy_cleanup(curl);
        } catch (...) {
            // swallow errors
        }
    }).detach();
}

std::vector<ScoreEntry> FetchHighscores(const std::string &gameType, int limit) {
    std::vector<ScoreEntry> out;
    try {
        CURL* curl = curl_easy_init();
        if (!curl) return out;

        std::string path = "highscores";
        // Clamp limit to max 10 to keep payloads small
        int l = std::clamp(limit, 1, 10);
        std::string query;
        if (!gameType.empty()) {
            if (gameType == "challenge") {
                query = "?game_type=eq." + gameType + "&order=level.desc,time_sec.asc&limit=" + std::to_string(l);
            } else {
                query = "?game_type=eq." + gameType + "&order=score.desc&limit=" + std::to_string(l);
            }
        } else {
            query = "?order=score.desc&limit=" + std::to_string(l);
        }

        std::string url = buildUrl(path) + query;

        struct curl_slist *headers = nullptr;
        headers = curl_slist_append(headers, ("apikey: " + SUPABASE_ANON_KEY).c_str());
        headers = curl_slist_append(headers, ("Authorization: Bearer " + SUPABASE_ANON_KEY).c_str());
        headers = curl_slist_append(headers, "Content-Type: application/json");


        std::string resp;
        curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
        curl_easy_setopt(curl, CURLOPT_TIMEOUT, 5L);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlWriteCallback);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &resp);

        if (g_verbose) std::cerr << "[Supabase] GET " << url << "\n";

        CURLcode res = curl_easy_perform(curl);
        if (res == CURLE_OK) {
            long http_code = 0;
            curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
            if (g_verbose) {
                std::cerr << "[Supabase] GET response code: " << http_code << " body_len=" << resp.size() << "\n";
                if (!resp.empty()) std::cerr << "[Supabase] GET response: " << resp << "\n";
            }
            try {
                auto j = json::parse(resp);
                if (j.is_array()) {
                    for (auto &v : j) {
                        ScoreEntry e{};
                        if (v.contains("score")) e.score = v["score"].get<int>();
                        if (v.contains("lines")) e.lines = v["lines"].get<int>();
                        if (v.contains("level")) e.level = v["level"].get<int>();
                        if (v.contains("time_sec")) {
                            try { e.timeSec = v["time_sec"].get<double>(); } catch(...) { e.timeSec = v["time_sec"].get<int>(); }
                        } else if (v.contains("timestamp")) {
                            e.timeSec = v["timestamp"].get<int>();
                        }
                        if (v.contains("name")) e.name = v["name"].get<std::string>();
                        if (v.contains("game_type")) e.gameType = v["game_type"].get<std::string>();
                        out.push_back(e);
                    }
                }
            } catch (...) {
                if (g_verbose) std::cerr << "[Supabase] GET parse error" << std::endl;
            }
        } else {
            if (g_verbose) std::cerr << "[Supabase] GET error: " << curl_easy_strerror(res) << "\n";
        }

        curl_slist_free_all(headers);
        curl_easy_cleanup(curl);
    } catch (...) {
        // swallow
    }
    return out;
}

} // namespace supabase
