#include "core/layout_storage_sqlite.h"
#include <sqlite3.h>
#include <chrono>
#include <ctime>
#include <iomanip>
#include <sstream>

namespace fn_ui {

// ── Helpers ───────────────────────────────────────────────────────────────

static std::string now_iso() {
    auto t = std::chrono::system_clock::to_time_t(
                 std::chrono::system_clock::now());
    std::tm tm_utc{};
#if defined(_WIN32)
    gmtime_s(&tm_utc, &t);
#else
    gmtime_r(&t, &tm_utc);
#endif
    std::ostringstream ss;
    ss << std::put_time(&tm_utc, "%Y-%m-%dT%H:%M:%SZ");
    return ss.str();
}

// ── API ───────────────────────────────────────────────────────────────────

bool layout_storage_init(sqlite3* db) {
    if (!db) return false;
    const char* sql =
        "CREATE TABLE IF NOT EXISTS ui_layouts ("
        "  name       TEXT PRIMARY KEY,"
        "  blob       TEXT NOT NULL,"
        "  created_at TEXT NOT NULL,"
        "  updated_at TEXT NOT NULL"
        ");";
    char* errmsg = nullptr;
    int rc = sqlite3_exec(db, sql, nullptr, nullptr, &errmsg);
    if (errmsg) sqlite3_free(errmsg);
    return rc == SQLITE_OK;
}

std::vector<std::string> layout_storage_list(sqlite3* db) {
    std::vector<std::string> out;
    if (!db) return out;

    const char* sql = "SELECT name FROM ui_layouts ORDER BY name;";
    sqlite3_stmt* stmt = nullptr;
    if (sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr) != SQLITE_OK) return out;

    while (sqlite3_step(stmt) == SQLITE_ROW) {
        const unsigned char* s = sqlite3_column_text(stmt, 0);
        if (s) out.push_back(reinterpret_cast<const char*>(s));
    }
    sqlite3_finalize(stmt);
    return out;
}

bool layout_storage_save(sqlite3* db, const std::string& name, const std::string& blob) {
    if (!db || name.empty()) return false;

    const std::string ts = now_iso();

    // UPSERT que preserva created_at original cuando ya existe.
    const char* sql =
        "INSERT INTO ui_layouts (name, blob, created_at, updated_at) "
        "VALUES (?, ?, ?, ?) "
        "ON CONFLICT(name) DO UPDATE SET "
        "  blob       = excluded.blob,"
        "  updated_at = excluded.updated_at;";

    sqlite3_stmt* stmt = nullptr;
    if (sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr) != SQLITE_OK) return false;

    sqlite3_bind_text(stmt, 1, name.c_str(), -1, SQLITE_TRANSIENT);
    sqlite3_bind_text(stmt, 2, blob.c_str(), -1, SQLITE_TRANSIENT);
    sqlite3_bind_text(stmt, 3, ts.c_str(),   -1, SQLITE_TRANSIENT); // created_at (ignorado en update)
    sqlite3_bind_text(stmt, 4, ts.c_str(),   -1, SQLITE_TRANSIENT); // updated_at

    int rc = sqlite3_step(stmt);
    sqlite3_finalize(stmt);
    return rc == SQLITE_DONE;
}

std::string layout_storage_load_blob(sqlite3* db, const std::string& name) {
    if (!db || name.empty()) return "";

    const char* sql = "SELECT blob FROM ui_layouts WHERE name = ?;";
    sqlite3_stmt* stmt = nullptr;
    if (sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr) != SQLITE_OK) return "";

    sqlite3_bind_text(stmt, 1, name.c_str(), -1, SQLITE_TRANSIENT);

    std::string result;
    if (sqlite3_step(stmt) == SQLITE_ROW) {
        const unsigned char* s = sqlite3_column_text(stmt, 0);
        if (s) result = reinterpret_cast<const char*>(s);
    }
    sqlite3_finalize(stmt);
    return result;
}

bool layout_storage_delete(sqlite3* db, const std::string& name) {
    if (!db || name.empty()) return false;

    const char* sql = "DELETE FROM ui_layouts WHERE name = ?;";
    sqlite3_stmt* stmt = nullptr;
    if (sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr) != SQLITE_OK) return false;

    sqlite3_bind_text(stmt, 1, name.c_str(), -1, SQLITE_TRANSIENT);

    int rc      = sqlite3_step(stmt);
    int changes = sqlite3_changes(db);
    sqlite3_finalize(stmt);
    return rc == SQLITE_DONE && changes > 0;
}

bool layout_storage_exists(sqlite3* db, const std::string& name) {
    if (!db || name.empty()) return false;

    const char* sql = "SELECT 1 FROM ui_layouts WHERE name = ? LIMIT 1;";
    sqlite3_stmt* stmt = nullptr;
    if (sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr) != SQLITE_OK) return false;

    sqlite3_bind_text(stmt, 1, name.c_str(), -1, SQLITE_TRANSIENT);

    bool found = (sqlite3_step(stmt) == SQLITE_ROW);
    sqlite3_finalize(stmt);
    return found;
}

} // namespace fn_ui
