#pragma once

#include <string>
#include <vector>
#include <variant>
#include <optional>
#include <memory>
#include <unordered_map>

struct sqlite3;
struct lua_State;

namespace mosis {

// SQL value types
using SqlValue = std::variant<std::nullptr_t, int64_t, double, std::string, std::vector<uint8_t>>;
using SqlRow = std::vector<SqlValue>;
using SqlResult = std::vector<SqlRow>;

struct DatabaseLimits {
    size_t max_database_size = 50 * 1024 * 1024;  // 50 MB per database
    int max_databases_per_app = 5;                 // Max open databases
    int max_query_time_ms = 5000;                  // 5 second query timeout
    int max_result_rows = 10000;                   // Max rows returned
};

class DatabaseHandle;

class DatabaseManager {
public:
    DatabaseManager(const std::string& app_id,
                    const std::string& app_root,
                    const DatabaseLimits& limits = DatabaseLimits{});
    ~DatabaseManager();

    // Database operations
    std::shared_ptr<DatabaseHandle> Open(const std::string& name, std::string& error);
    void CloseAll();

    // Stats
    size_t GetOpenDatabaseCount() const;

private:
    std::string m_app_id;
    std::string m_app_root;
    DatabaseLimits m_limits;
    std::unordered_map<std::string, std::shared_ptr<DatabaseHandle>> m_databases;

    std::string ResolvePath(const std::string& name);
    bool ValidateName(const std::string& name, std::string& error);
};

class DatabaseHandle {
public:
    DatabaseHandle(sqlite3* db, const std::string& path, const DatabaseLimits& limits);
    ~DatabaseHandle();

    // Execute (INSERT, UPDATE, DELETE, CREATE, etc.)
    bool Execute(const std::string& sql, const std::vector<SqlValue>& params, std::string& error);

    // Query (SELECT)
    std::optional<SqlResult> Query(const std::string& sql, const std::vector<SqlValue>& params,
                                    std::string& error);

    // Get last insert rowid
    int64_t GetLastInsertRowId() const;

    // Get affected rows
    int GetChanges() const;

    bool IsOpen() const { return m_db != nullptr; }
    void Close();

private:
    sqlite3* m_db;
    std::string m_path;
    DatabaseLimits m_limits;

    static int Authorizer(void* user_data, int action, const char* arg1,
                          const char* arg2, const char* arg3, const char* arg4);

    bool BindParameters(void* stmt, const std::vector<SqlValue>& params, std::string& error);
};

// Register database.* APIs as globals
void RegisterDatabaseAPI(lua_State* L, DatabaseManager* manager);

} // namespace mosis
