-- laundering/sv_storage.lua
-- Persistance SQLite des positions de NPCs.
-- API interne : SaveNPC, RemoveNPC, LoadNPCsForMap, ListAllNPCs

Laundering         = Laundering or {}
Laundering.Storage = Laundering.Storage or {}

local TABLE_NAME = "laundering_npcs"

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

function Laundering.Storage.Init()
    local q = [[
        CREATE TABLE IF NOT EXISTS laundering_npcs (
            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("[Laundering] Erreur SQL création table : " .. sql.LastError() .. "\n")
        return
    end

    sql.Query("CREATE INDEX IF NOT EXISTS idx_laundering_npcs_map ON laundering_npcs(map)")

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

    print("[Laundering] Schéma SQLite initialisé (version 1).")
end

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

function Laundering.Storage.SaveNPC(mapName, vec, angY)
    local q = string.format(
        "INSERT INTO laundering_npcs (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("[Laundering] Storage.SaveNPC erreur SQL : " .. sql.LastError() .. "\n")
        return nil
    end

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

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

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

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

-- ============================================================================
-- LoadNPCsForMap — retourne { {id, x, y, z, angle_y}, ... } pour la map courante
-- ============================================================================

function Laundering.Storage.LoadNPCsForMap(mapName)
    local q = string.format(
        "SELECT id, x, y, z, angle_y FROM laundering_npcs WHERE map = %s",
        sql.SQLStr(tostring(mapName))
    )
    local rows = sql.Query(q)
    if rows == false then
        ErrorNoHalt("[Laundering] Storage.LoadNPCsForMap 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

-- ============================================================================
-- ListAllNPCs — retourne tous les NPCs toutes maps confondues (outil admin)
-- ============================================================================

function Laundering.Storage.ListAllNPCs()
    local rows = sql.Query("SELECT id, map, x, y, z, angle_y FROM laundering_npcs ORDER BY map, id")
    if rows == false then
        ErrorNoHalt("[Laundering] Storage.ListAllNPCs 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
