-- laundromat/sv_storage.lua
-- Persistance SQLite des positions de machines.
-- API : SaveMachine / RemoveMachine / LoadMachinesForMap / ListAllMachines
-- NOTE : sql.SQLStr(value) SANS le 2e argument "true" (noQuotes).
--        Passer true briserait les strings non-numériques comme "gm_construct".

Laundromat         = Laundromat         or {}
Laundromat.Storage = Laundromat.Storage or {}

-- ============================================================================
-- Initialisation du schéma
-- ============================================================================

function Laundromat.Storage.Init()
    local q = [[
        CREATE TABLE IF NOT EXISTS laundromat_machines (
            id      INTEGER PRIMARY KEY AUTOINCREMENT,
            map     TEXT    NOT NULL,
            x       REAL    NOT NULL,
            y       REAL    NOT NULL,
            z       REAL    NOT NULL,
            angle_y REAL    NOT NULL
        )
    ]]
    local res = sql.Query(q)
    if res == false then
        ErrorNoHalt("[Laundromat] Erreur SQL création table : " .. sql.LastError() .. "\n")
        return
    end

    sql.Query("CREATE INDEX IF NOT EXISTS idx_laundromat_machines_map ON laundromat_machines(map)")

    -- Schema versioning
    local ver = sql.QueryValue("PRAGMA user_version")
    if tonumber(ver) == 0 then
        sql.Query("PRAGMA user_version = 1")
    end

    if Laundromat.Config and Laundromat.Config.Logs then
        print("[Laundromat] Schéma SQLite initialisé (version 1).")
    end
end

-- ============================================================================
-- SaveMachine — insère une nouvelle ligne, retourne l'id
-- ============================================================================

function Laundromat.Storage.SaveMachine(mapName, vec, angY)
    local q = string.format(
        "INSERT INTO laundromat_machines (map, x, y, z, angle_y) VALUES (%s, %f, %f, %f, %f)",
        sql.SQLStr(tostring(mapName)),
        tonumber(vec.x) or 0,
        tonumber(vec.y) or 0,
        tonumber(vec.z) or 0,
        tonumber(angY)  or 0
    )
    local res = sql.Query(q)
    if res == false then
        ErrorNoHalt("[Laundromat] Storage.SaveMachine erreur SQL : " .. sql.LastError() .. "\n")
        return nil
    end

    local newID = sql.QueryValue("SELECT last_insert_rowid()")
    return tonumber(newID)
end

-- ============================================================================
-- RemoveMachine — supprime par id, retourne bool
-- ============================================================================

function Laundromat.Storage.RemoveMachine(id)
    id = math.floor(tonumber(id) or 0)
    if id <= 0 then return false end

    local q   = string.format("DELETE FROM laundromat_machines WHERE id = %d", id)
    local res = sql.Query(q)
    if res == false then
        ErrorNoHalt("[Laundromat] Storage.RemoveMachine erreur SQL : " .. sql.LastError() .. "\n")
        return false
    end
    return true
end

-- ============================================================================
-- LoadMachinesForMap — retourne { {id, x, y, z, angle_y}, ... }
-- ============================================================================

function Laundromat.Storage.LoadMachinesForMap(mapName)
    local q = string.format(
        "SELECT id, x, y, z, angle_y FROM laundromat_machines WHERE map = %s",
        sql.SQLStr(tostring(mapName))
    )
    local rows = sql.Query(q)
    if rows == false then
        ErrorNoHalt("[Laundromat] Storage.LoadMachinesForMap erreur SQL : " .. sql.LastError() .. "\n")
        return {}
    end
    if not rows then return {} end

    local result = {}
    for _, row in ipairs(rows) do
        result[#result + 1] = {
            id      = tonumber(row.id),
            x       = tonumber(row.x)       or 0,
            y       = tonumber(row.y)       or 0,
            z       = tonumber(row.z)       or 0,
            angle_y = tonumber(row.angle_y) or 0,
        }
    end
    return result
end

-- ============================================================================
-- ListAllMachines — retourne toutes les machines toutes maps (outil admin)
-- ============================================================================

function Laundromat.Storage.ListAllMachines()
    local rows = sql.Query("SELECT id, map, x, y, z, angle_y FROM laundromat_machines ORDER BY map, id")
    if rows == false then
        ErrorNoHalt("[Laundromat] Storage.ListAllMachines erreur SQL : " .. sql.LastError() .. "\n")
        return {}
    end
    if not rows then return {} end

    local result = {}
    for _, row in ipairs(rows) do
        result[#result + 1] = {
            id      = tonumber(row.id),
            map     = row.map,
            x       = tonumber(row.x)       or 0,
            y       = tonumber(row.y)       or 0,
            z       = tonumber(row.z)       or 0,
            angle_y = tonumber(row.angle_y) or 0,
        }
    end
    return result
end
