// Scores.cpp - Implementation of ScoreManager with Firebase Sync
#include "Scores.h"
#include <SDL3/SDL.h>
#include <fstream>
#include <sstream>
#include <algorithm>
#include <cpr/cpr.h>
#include <nlohmann/json.hpp>
#include <iostream>
#include <thread>
#include <ctime>

using json = nlohmann::json;

// Firebase Realtime Database URL
const std::string FIREBASE_URL = "https://tetris-90139.firebaseio.com/scores.json";

ScoreManager::ScoreManager(size_t maxScores) : maxEntries(maxScores) {}

std::string ScoreManager::filePath() const {
    static std::string path; if (!path.empty()) return path;
    char* base = SDL_GetPrefPath("example","spacetris_sdl3");
    if (base) { path = std::string(base)+"highscores.txt"; SDL_free(base);} else path="highscores.txt";
    return path;
}

void ScoreManager::load() {
    scores.clear();
    
    // Try to load from Firebase first
    try {
        cpr::Response r = cpr::Get(cpr::Url{FIREBASE_URL}, cpr::Timeout{2000}); // 2s timeout
        if (r.status_code == 200 && !r.text.empty() && r.text != "null") {
            auto j = json::parse(r.text);
            
            // Firebase returns a map of auto-generated IDs to objects
            if (j.is_object()) {
                for (auto& [key, value] : j.items()) {
                    ScoreEntry e;
                    if (value.contains("score")) e.score = value["score"];
                    if (value.contains("lines")) e.lines = value["lines"];
                    if (value.contains("level")) e.level = value["level"];
                    if (value.contains("timeSec")) e.timeSec = value["timeSec"];
                    if (value.contains("name")) e.name = value["name"];
                    scores.push_back(e);
                }
            } 
            // Or it might be an array if keys are integers (unlikely for Firebase push)
            else if (j.is_array()) {
                for (auto& value : j) {
                    ScoreEntry e;
                    if (value.contains("score")) e.score = value["score"];
                    if (value.contains("lines")) e.lines = value["lines"];
                    if (value.contains("level")) e.level = value["level"];
                    if (value.contains("timeSec")) e.timeSec = value["timeSec"];
                    if (value.contains("name")) e.name = value["name"];
                    scores.push_back(e);
                }
            }
            
            // Sort and keep top scores
            std::sort(scores.begin(), scores.end(), [](auto&a,auto&b){return a.score>b.score;});
            if (scores.size() > maxEntries) scores.resize(maxEntries);
            
            // Save to local cache
            save();
            return;
        }
    } catch (...) {
        // Ignore network errors and fall back to local file
        std::cerr << "Failed to load from Firebase, falling back to local file." << std::endl;
    }

    // Fallback to local file
    std::ifstream f(filePath()); 
    if (!f) {
        // Create sample high scores if file doesn't exist
        createSampleScores();
        save();
        return;
    }
    
    std::string line; 
    while (std::getline(f, line)) { 
        std::istringstream iss(line); 
        ScoreEntry e; 
        iss >> e.score >> e.lines >> e.level >> e.timeSec;
        if (iss) {
            // Try to read name (rest of line after timeSec)
            std::string remaining;
            std::getline(iss, remaining);
            if (!remaining.empty() && remaining[0] == ' ') {
                e.name = remaining.substr(1); // Remove leading space
            }
            scores.push_back(e);
        }
        if (scores.size() >= maxEntries) break; 
    }
    
    if (scores.empty()) {
        createSampleScores();
        save();
    }
    
    std::sort(scores.begin(), scores.end(), [](auto&a,auto&b){return a.score>b.score;});
}

void ScoreManager::save() const {
    std::ofstream f(filePath(), std::ios::trunc);
    for (auto &e : scores) {
        f << e.score << ' ' << e.lines << ' ' << e.level << ' ' << e.timeSec << ' ' << e.name << '\n';
    }
}

void ScoreManager::submit(int score, int lines, int level, double timeSec, const std::string& name) {
    // Add to local list
    scores.push_back(ScoreEntry{score,lines,level,timeSec, name});
    std::sort(scores.begin(), scores.end(), [](auto&a,auto&b){return a.score>b.score;});
    if (scores.size()>maxEntries) scores.resize(maxEntries);
    save();
    
    // Submit to Firebase
    // Run in a detached thread to avoid blocking the UI? 
    // For simplicity, we'll do it blocking for now, or rely on short timeout.
    // Ideally this should be async.
    
    json j;
    j["score"] = score;
    j["lines"] = lines;
    j["level"] = level;
    j["timeSec"] = timeSec;
    j["name"] = name;
    j["timestamp"] = std::time(nullptr); // Add timestamp
    
    // Fire and forget (async) would be better, but for now let's just try to send
    // We can use std::thread to make it async
    std::thread([j]() {
        try {
            cpr::Post(cpr::Url{FIREBASE_URL}, 
                      cpr::Body{j.dump()}, 
                      cpr::Header{{"Content-Type", "application/json"}},
                      cpr::Timeout{5000});
        } catch (...) {
            // Ignore errors
        }
    }).detach();
}

bool ScoreManager::isHighScore(int score) const {
    if (scores.size() < maxEntries) return true;
    return score > scores.back().score;
}

void ScoreManager::createSampleScores() {
    scores = {
        {159840, 189, 14, 972, "GREGOR"},
        {156340, 132, 12, 714, "GREGOR"}, 
        {155219, 125, 12, 696, "GREGOR"},
        {141823, 123, 10, 710, "GREGOR"},
        {140079, 71, 11, 410, "GREGOR"},
        {116012, 121, 10, 619, "GREGOR"},
        {112643, 137, 13, 689, "GREGOR"},
        {99190, 61, 10, 378, "GREGOR"},
        {93648, 107, 10, 629, "GREGOR"},
        {89041, 115, 10, 618, "GREGOR"},
        {88600, 55, 9, 354, "GREGOR"},
        {86346, 141, 13, 723, "GREGOR"}
    };
}
