-- laundromat/sv_machine.lua
-- Spawn et chargement initial des machines depuis la base de données.
-- SpawnMachine : crée l'entité et retourne la référence.
-- InitPostEntity : chargé au démarrage du serveur après que les entités sont prêtes.

Laundromat          = Laundromat          or {}
Laundromat._machines = Laundromat._machines or {}  -- [entity] = dbId
Laundromat._shutting = false

hook.Add("ShutDown", "Laundromat.MarkShutdown", function()
    Laundromat._shutting = true
end)

-- ============================================================================
-- SpawnMachine — crée l'entité laundromat_machine
-- pos     : Vector
-- angY    : number (yaw)
-- dbId    : number|nil (id SQLite, nil si non persisté)
-- returns : entity | nil
-- ============================================================================

function Laundromat.SpawnMachine(pos, angY, dbId)
    local ent = ents.Create("laundromat_machine")
    if not IsValid(ent) then
        ErrorNoHalt("[Laundromat] Impossible de créer l'entité laundromat_machine.\n")
        return nil
    end

    ent:SetPos(pos)
    ent:SetAngles(Angle(0, tonumber(angY) or 0, 0))
    ent:Spawn()
    ent:Activate()

    -- Référence pour la gestion des machines
    ent.LaundromatMachineID = dbId
    Laundromat._machines[ent] = dbId

    if Laundromat.Config and Laundromat.Config.Logs then
        print(string.format(
            "[Laundromat] Machine #%s spawné à (%.0f, %.0f, %.0f) yaw=%.1f",
            tostring(dbId or "?"), pos.x, pos.y, pos.z, tonumber(angY) or 0
        ))
    end

    return ent
end

-- ============================================================================
-- InitPostEntity — chargement des machines de la map courante depuis la DB
-- ============================================================================

hook.Add("InitPostEntity", "Laundromat.LoadMachines", function()
    local mapName = game.GetMap()
    local rows    = Laundromat.Storage.LoadMachinesForMap(mapName)

    local count = 0
    for _, row in ipairs(rows) do
        local pos = Vector(row.x, row.y, row.z)
        local ent = Laundromat.SpawnMachine(pos, row.angle_y, row.id)
        if IsValid(ent) then
            count = count + 1
        end
    end

    if Laundromat.Config and Laundromat.Config.Logs then
        print(string.format(
            "[Laundromat] %d machine(s) chargée(s) sur '%s'.",
            count, mapName
        ))
    end
end)

-- ============================================================================
-- EntityRemoved : auto-respawn si la machine est virée par un cleanup global
-- Sandbox (`cleanup` console), lua_run, ou autre mécanisme externe.
-- On respawn UNIQUEMENT si la suppression n'est pas marquée _intentionalRemove
-- (par laundromat_remove ou laundromat_cleanup) et si la row existe encore en DB.
-- ============================================================================

hook.Add("EntityRemoved", "Laundromat.RespawnOnUnexpectedRemoval", function(ent)
    if not IsValid(ent) then return end
    if ent:GetClass() ~= "laundromat_machine" then return end

    -- Toujours retirer de la table interne
    Laundromat._machines[ent] = nil

    -- Skip si suppression volontaire ou shutdown serveur
    if ent._intentionalRemove then return end
    if Laundromat._shutting then return end

    -- Respawn différé (laisser le tick courant finir)
    local id = ent.LaundromatMachineID
    if not id then return end

    timer.Simple(0.1, function()
        if Laundromat._shutting then return end

        -- Vérifier que la row existe encore en DB
        local rows = Laundromat.Storage.LoadMachinesForMap(game.GetMap())
        for _, row in ipairs(rows) do
            if row.id == id then
                Laundromat.SpawnMachine(Vector(row.x, row.y, row.z), row.angle_y, row.id)
                if Laundromat.Config and Laundromat.Config.Logs then
                    print(string.format("[Laundromat] Machine #%d respawnée (cleanup externe détecté).", id))
                end
                return
            end
        end
    end)
end)
