local impostores = {}
local jugadores_activos = {}
local juego_iniciado = false
local juego_activo = false
local mod_name = core.get_current_modname()
local mod_path = core.get_modpath(mod_name)
local votaciones_activas = false
local votos = {}
local mensaje = true
local tiempo_votacion = 60
local TIEMPO_LIMITE = 720
local PAUSA_REINICIO = 3
local tiempo_restante = TIEMPO_LIMITE
local jugadores_esperando = {} 
local temporizador_global = nil
local cooldown = 60
local last_used = {}
local last_used_global = 0  
local player_cursor_huds = {}


function impostor(player)
    local name = player:get_player_name()
    score_hud_id = player:hud_add({
        type = "image",
        name = "custom_cursor_" .. name,
        text = "impostor.png",
        scale = {x=0.6, y=0.6},
        alignment = {x=0, y=0},
        offset = {x=50, y=50},
        position = {x = 0.43, y = 0.47},
    })
    minetest.after(3, function()
         player:hud_remove(score_hud_id)
    end)
end

function trabajador(player)
    local name = player:get_player_name()
    score_hud_id = player:hud_add({
        type = "image",
        name = "custom_cursor_" .. name,
        text = "worker.png",
        scale = {x=0.6, y=0.6},
        alignment = {x=0, y=0},
        offset = {x=50, y=50},
        position = {x = 0.48, y = 0.47},
    })
    minetest.after(3, function()
         player:hud_remove(score_hud_id)
    end)
end

local function contar_impostores_vivos()
    local count = 0
    for name, is_impostor in pairs(impostores) do
        if is_impostor and jugadores_activos[name] then
            count = count + 1
        end
    end
    return count
end

local function contar_trabajadores_vivos()
    local count = 0
    for name, is_impostor in pairs(impostores) do
        if not is_impostor and jugadores_activos[name] then
            count = count + 1
        end
    end
    return count
end

function verificar_estado_juego()

    if not juego_activo then return end

    local impostores_vivos = contar_impostores_vivos()
    local trabajadores_vivos = contar_trabajadores_vivos()

    if impostores_vivos <= 0 then
        juego_activo = false
        core.chat_send_all(core.colorize("#FFA500","[Game] All impostors eliminated! The workers win."))
        if temporizador_global then
            core.after(0, function() core.unregister_globalstep(temporizador_global) end)
            temporizador_global = nil 
        end
        core.after(PAUSA_REINICIO, function()
            reiniciar_juego()
        end)
        return
    end
    if trabajadores_vivos <= impostores_vivos then 
        juego_activo = false
        core.chat_send_all(core.colorize("#FFA500","[Game] Impostors outnumber workers! The impostors win."))
        if temporizador_global then

            core.after(0, function() core.unregister_globalstep(temporizador_global) end)
            temporizador_global = nil 
        end

        core.after(PAUSA_REINICIO, function()
            reiniciar_juego()
        end)
        return
    end

    if tiempo_restante <= 0 and juego_activo then 
         juego_activo = false 
         core.chat_send_all(core.colorize("#FFA500","[Game] Time out! The impostors win."))
         if temporizador_global then
            core.after(0, function() core.unregister_globalstep(temporizador_global) end)
             temporizador_global = nil
        end
         core.after(PAUSA_REINICIO, function()
            reiniciar_juego()
        end)
         return
    end

end

function reiniciar_juego()
    last_used_global = 0
    impostores = {}
    jugadores_activos = {}
    tiempo_restante = TIEMPO_LIMITE
    juego_iniciado = false
    juego_activo = true
    votaciones_activas = false
    votos = {}
    last_used = {}

    if temporizador_global then
         core.unregister_globalstep(temporizador_global)
         temporizador_global = nil
    end

    local players_for_next_game = {}

    for _, player in ipairs(core.get_connected_players()) do
        local name = player:get_player_name()

        player:set_properties({visual_size = {x = 1, y = 1}})
        player:set_physics_override({speed = 1,jump = 1,gravity = 1})
        local pos = {x = 12, y = -12, z = -15} 
        player:set_pos(pos)

        table.insert(players_for_next_game, player)

        if jugadores_esperando[name] then
            jugadores_esperando[name] = nil
        end
    end

    jugadores_esperando = {}

    asignar_roles(players_for_next_game)
    dar_priv()
end

core.register_on_leaveplayer(function(player)
    local name = player:get_player_name()
    if jugadores_esperando[name] then
        jugadores_esperando[name] = nil
    end

    if jugadores_activos[name] then
        jugadores_activos[name] = false
        verificar_estado_juego() 
    end
end)

function asignar_roles(players_to_assign)
    dar_priv()
    mensaje = false
    quitar_cadaver()

    if juego_iniciado then
         core.chat_send_all(core.colorize("#FFA500","[Game] El juego ya comenzo. Debes esperar a que termine."))
         return
    end

    
    local players = players_to_assign or core.get_connected_players() 
    juego_iniciado = false 
    juego_activo = false
    juego_iniciado = true
    juego_activo = true

    local num_impostores = math.min(3, math.max(1, math.ceil(#players / 4)))

    local candidates = {}
    for _, player in ipairs(players) do
        table.insert(candidates, player:get_player_name())
    end

    impostores = {}
    jugadores_activos = {}

    for i = #candidates, 2, -1 do
        local j = math.random(i)
        candidates[i], candidates[j] = candidates[j], candidates[i]
    end

    for i = 1, num_impostores do
        local name = candidates[i]
        impostores[name] = true
        jugadores_activos[name] = true 
        local player = core.get_player_by_name(name)
        if player then
            core.chat_send_player(name,minetest.colorize("#FFA500","[Game] You are an IMPOSTER,kill the workers"))
             impostor(player)
             dar_item_especial(player)
             player:set_pos({x = 12, y = -12, z = -15})
        end
    end

    for i = num_impostores+1, #candidates do
        local name = candidates[i]
        impostores[name] = false
        jugadores_activos[name] = true
         local player = core.get_player_by_name(name)
        if player then
            core.chat_send_player(name,minetest.colorize("#FFA500","[Game] You are hardworking, do the tasks to earn"))
             trabajador(player)
             quitar_item_jugador(player)
             player:set_pos({x = 12, y = -12, z = -15})
        end
    end

    tiempo_restante = TIEMPO_LIMITE
    if temporizador_global then
         core.unregister_globalstep(temporizador_global)
         temporizador_global = nil
    end

    temporizador_global = core.register_globalstep(function(dtime)
        if juego_activo and not votaciones_activas then
            tiempo_restante = tiempo_restante - dtime
            if tiempo_restante <= 0 then
                tiempo_restante = 0 
                verificar_estado_juego()
            end
        end
    end)
end

local function mostrar_formspec_votacion(player,iniciador)
    quitar_cadaver()
    local pname = player:get_player_name()
    if not jugadores_activos[pname] then
        return
    end

    local formspec = {
        "size[13,9]",
        "font[,#000000]", -- <-- AÑADIDO: Cambia el color de la fuente a negro (#000000)
        "label[5,0.1;EMERGENCY MEETING]",
        "label[5,1.1;select a suspicious player:]",
        "background[0,0;13,9;background_forsmpecs.png;1]",
        "button_exit[5.5,8;2,1;;finish]"
    }

    local y_pos = 2.0

    for name, activo in pairs(jugadores_activos) do
        if activo and name ~= pname then
            table.insert(formspec, "button[0.5,"..y_pos..";2,1;votar_"..name..";"..name.."]")
            y_pos = y_pos + 1.1
        end
    end

    table.insert(formspec, "button[0.5,8;2,1;votar_skip;do not vote]")
    table.insert(formspec, "label[5.5,0.6;started by:"..iniciador.."]")
    table.insert(formspec, "label[8,8;time to vote: "..tiempo_votacion.." seconds]")

    core.show_formspec(pname, "one_of_us:votacion_emergencia", table.concat(formspec, ""))

end

local function iniciar_votacion_emergencia(iniciador)
    if votaciones_activas then
        core.chat_send_player(iniciador,minetest.colorize("#FFA500","[Game] There is already a vote in progress"))
        return
    end

    if not juego_activo then
        core.chat_send_player(iniciador,minetest.colorize("#FFA500","[Game] Cannot start voting - game not active"))
        return
    end


    if not jugadores_activos[iniciador] then
        core.chat_send_player(iniciador,minetest.colorize("#FFA500","[Game] Only active players can start a meeting."))
        return
    end

    votaciones_activas = true
    votos = {} 

    local active_players_count = 0
    for name, activo in pairs(jugadores_activos) do
        if activo then
            active_players_count = active_players_count + 1
            local player = core.get_player_by_name(name)
            if player then

                 core.close_formspec(name, "one_of_us:votacion_emergencia")
                 core.close_formspec(name, "one_of_us:RESULTADOS")
                mostrar_formspec_votacion(player, iniciador)
            end
        end
    end

    if active_players_count < 2 then
        core.chat_send_all(core.colorize("#FFA500","[Game] There are not enough active players to vote. Voting ends."))
        votaciones_activas = false
        votos = {}

        if temporizador_global then

        end
        return
    end

    local tiempo_restante_votacion = tiempo_votacion
    local voting_timer_handle = core.register_globalstep(function(dtime)
        if votaciones_activas then 
            tiempo_restante_votacion = tiempo_restante_votacion - dtime

            if tiempo_restante_votacion <= 0 then
                tiempo_restante_votacion = 0 

                one_of_us()

                if voting_timer_handle then
                     core.unregister_globalstep(voting_timer_handle)
                     voting_timer_handle = nil 
                end
                return
            end
        else

             if voting_timer_handle then
                core.unregister_globalstep(voting_timer_handle)
                voting_timer_handle = nil 
             end
        end
    end)

end

core.register_on_player_receive_fields(function(player, formname, fields)

    if not votaciones_activas or formname ~= "one_of_us:votacion_emergencia" then
        return false 
    end

    local pname = player:get_player_name()

     if not jugadores_activos[pname] then
        core.chat_send_player(pname,minetest.colorize("#FFA500","[Game] You are not an active player and cannot vote."))
        core.close_formspec(pname, "one_of_us:votacion_emergencia") 
        return false
     end

    if votos[pname] then
        core.chat_send_player(pname, "¡Ya has votado!")
        return true
    end

    for field, _ in pairs(fields) do
        if field:sub(1, 6) == "votar_" then
            local votado = field:sub(7)
            if votado == "skip" then
                votos[pname] = "skip"
                 core.chat_send_player(pname,minetest.colorize("#FFA500","[Game] You decided not to vote"))
                 core.close_formspec(pname, "one_of_us:votacion_emergencia") 
            else

                if jugadores_activos[votado] then
                    votos[pname] = votado
                    core.chat_send_player(pname,minetest.colorize("#FFA500","[Game] voted for: "..votado))
                     core.close_formspec(pname, "one_of_us:votacion_emergencia") 
                else
                     core.chat_send_player(pname,minetest.colorize("#FFA500","[Game] That player is not active"))
                     return false 
                end
            end

            local active_voters_count = 0
            for name, activo in pairs(jugadores_activos) do
                if activo then
                    active_voters_count = active_voters_count + 1
                end
            end
            local votes_count = 0
            for voter, _ in pairs(votos) do
                votes_count = votes_count + 1
            end

            if votes_count >= active_voters_count then
                 one_of_us()
            end

            return true
        end
    end

    if fields.finish then
         return true 
    end

    return false 
end)

function convertir_en_fanstasma(player)
    quitar_item_jugador(player)
    quitar_priv(player)
    if player then 
        player:set_pos({x = 12, y = -12, z = -15})
        player:set_properties({visual_size = {x = 0, y = 0}})
        player:set_physics_override({speed = 2,jump = 0,gravity = 0})
    end
end

function resultados(mas_votado, max_votos, sin_expulsiones, impostor)
    verificar_estado_juego()
    local mensaje_1 = ""
    local mensaje_2 = "" 

    if sin_expulsiones == false then
        mensaje_1 = "was expelled: \n"..mas_votado.." with "..max_votos.." votes"
    else
        mensaje_1 = "no one is expelled (omission or tie)"
    end

    if sin_expulsiones == false and impostor ~= nil then 
         if impostor then
            mensaje_2 = "he was the imposter"
         else
            mensaje_2 = "he was not the imposter"
         end
    end

    for _, player in ipairs(core.get_connected_players()) do
        local nombre = player:get_player_name()

        core.after(2, function()
            local p = core.get_player_by_name(nombre)
            if p then
                 local formspec = {
                    "size[13,9]",
                    "label[5.5,0;VOTING RESULTS]",
                    "background[0,0;13,9;background_forsmpecs.png;1]",
                    "button_exit[5.5,8;2,1;;finish]"
                 }

                 table.insert(formspec, "label[5.5,3;"..mensaje_1.."]")
                 if mensaje_2 ~= "" then
                     table.insert(formspec, "label[5,4;"..mensaje_2.."]")
                 end

                 core.show_formspec(nombre, "one_of_us:RESULTADOS", table.concat(formspec, ""))
            end
        end)
    end
end

function one_of_us()
    if not votaciones_activas then return end
    votaciones_activas = false

     for _, player in ipairs(core.get_connected_players()) do
        local name = player:get_player_name()
        core.close_formspec(name, "one_of_us:votacion_emergencia")
     end

    local conteo = {}
    local skip_votes = 0
    for voter, votado in pairs(votos) do
        if votado == "skip" then
            skip_votes = skip_votes + 1
        else

             if jugadores_activos[votado] then
                conteo[votado] = (conteo[votado] or 0) + 1
             end
        end
    end

    local mas_votado = nil
    local max_votos = 0
    local tie = false 

    for jugador, cantidad in pairs(conteo) do
        if cantidad > max_votos then
            max_votos = cantidad
            mas_votado = jugador
            tie = false 
        elseif cantidad == max_votos and cantidad > 0 then
            tie = true 
        end
    end

    local expelled_player = nil
    local sin_expulsiones = true
    local is_expelled_impostor = nil 

    if mas_votado and not tie then 
        expelled_player = mas_votado
        sin_expulsiones = false

        if jugadores_activos[expelled_player] then
            jugadores_activos[expelled_player] = false
            local player = core.get_player_by_name(expelled_player)
            if player then
                convertir_en_fanstasma(player)
            end

            is_expelled_impostor = impostores[expelled_player] == true
        end
    end

    core.after(PAUSA_REINICIO, function()
        resultados(expelled_player, max_votos, sin_expulsiones, is_expelled_impostor)
    end)

    core.after(PAUSA_REINICIO, function()
        verificar_estado_juego()
    end)
end


core.register_node("one_of_us:boton_emergencia", {
    description = "Botón de Emergencia",
    tiles = {"button_emergency.png"},
    on_rightclick = function(pos, node, clicker)
        local name = clicker:get_player_name()
        local current_time = minetest.get_gametime()

        if not jugadores_activos[name] then
            core.chat_send_player(name, "[Game] Solo jugadores activos pueden usar esto")
            return
        end

        local tiempo_restante = cooldown - (current_time - last_used_global)

        if tiempo_restante > 0 then
            core.chat_send_player(name, "[Game] The emergency button will be ready in: "..tiempo_restante.." seconds")
            return
        end
        for _, player in ipairs(minetest.get_connected_players()) do
            minetest.sound_play("alarm", {
            to_player = player:get_player_name(),
            gain = 1,
            })
        end
        iniciar_votacion_emergencia(name)
        last_used_global = current_time 
    end,
})

core.register_chatcommand("reset", {
    description = "Reinicia completamente el juego",
    privs = {server = true},
    func = function(name)
        reiniciar_juego()
    end,
})

if PAUSA_REINICIO == nil then
    local PAUSA_REINICIO = 3
end

minetest.register_on_joinplayer(function(player)
    quitar_item_jugador(player)
    music(player)
    player:set_pos({x = 12, y = -12, z = -15}) 
    local name = player:get_player_name()
    player:hud_set_flags({breathbar=false,minimap=false,crosshair=false,minimap_radar=false,healthbar = false,})
    player:set_stars({visible = false})
    player:set_sun({visible = true, sunrise_visible = false})
    player:set_moon({visible = false})
    player:hud_set_hotbar_image("hotbar.png") 
    player:hud_set_hotbar_selected_image("") 
    local inv = player:get_inventory()
    local name = player:get_player_name()
    local hud_id = player:hud_add({
        type = "image",
        name = "custom_cursor_" .. name,
        text = "cursor.png",
        scale = {x=0.2, y=0.2},
        alignment = {x=0, y=0},
        offset = {x=10, y=10},
        position = {x = 0.49, y = 0.47},
    })
    player_cursor_huds[name] = hud_id
    inv:set_list("main", {})
    inv:set_size("main", 1)
    inv:set_size("craft", 0) 
    inv:set_size("hand", 0) 
    if mensaje then
    core.chat_send_player(name,minetest.colorize("#FFA500","[Game] Get ready, the game is about to begin!"))
    end
    if juego_activo then
        core.chat_send_player(name,minetest.colorize("#FFA500","[Game] The game is in progress. wait the next round."))
        convertir_en_fanstasma(player)
        jugadores_esperando[name] = true 
        jugadores_activos[name] = false
        impostores[name] = nil 
        return
    end 
end)

minetest.register_allow_player_inventory_action(function(player, action, inventory, inventory_info)
    if action == "put" then
        local inv = player:get_inventory()
        if not inv:is_empty("main") then
            return 0 
        end
    end
    return 1 
end)

minetest.after(20, function()
    local connected_players = core.get_connected_players()
    mensaje = false
    asignar_roles(connected_players)
end)


local cooldown_tracker = {}
local COOLDOWN_TIME = 40 

function convertir_en_fanstasma_con_cuerpo(target_name)
    if target_name then 
        quitar_item_jugador(target_name)
        quitar_priv(target_name)
        target_name_pos = target_name:get_pos()
        target_name:set_pos({x = 12, y = -12, z = -15}) 
        target_name:set_properties({visual_size = {x = 0, y = 0}})
        target_name:set_physics_override({speed = 2,jump = 0,gravity = 0})
        cadaver(target_name_pos, target_name)
    end
end

minetest.register_tool("one_of_us:item_especial", {
    description = "Espada Especial",
    inventory_image = "sword1.png",
    wield_scale = {x = 1, y = 1, z = 1},
    tool_capabilities = {
        full_punch_interval = 1.0,
        max_drop_level = 1,
        groupcaps = {
            snappy = {times = {[1]=1.90, [2]=0.90, [3]=0.30}, uses = 40, maxlevel = 3},
        },
        damage_groups = {fleshy = 50},
    },
    
    on_drop = function(itemstack, dropper, pos)
        return itemstack
    end,   
    on_use = function(itemstack, user, pointed_thing)
        local player_name = user:get_player_name()
        local current_time = minetest.get_us_time()
        local last_used = cooldown_tracker[player_name]
        
        if last_used then
            local tiempo_transcurrido = (current_time - last_used) / 1000000 
            local tiempo_restante = COOLDOWN_TIME - tiempo_transcurrido
            
            if tiempo_restante > 0 then
                local mensaje = string.format("time left to kill: %.1f seconds", tiempo_restante)
                minetest.chat_send_player(player_name, mensaje)
                return  
            end
        end
        
        cooldown_tracker[player_name] = current_time
        if pointed_thing.type == "object" then
            local target = pointed_thing.ref
            local user_name = user:get_player_name()
            if target:is_player() then
                minetest.sound_play("knifesharpener1", {
                    to_player = target:get_player_name(),
                    gain = 1,
                })
                minetest.sound_play("knifesharpener1", {
                    to_player = user:get_player_name(),
                    gain = 1,
                })
                convertir_en_fanstasma_con_cuerpo(target)
                verificar_estado_juego()
            end
          end
        return itemstack
    end
})

function dar_item_especial(player)
    local inv = player:get_inventory()
    if inv:room_for_item("main", "one_of_us:item_especial") then
        inv:add_item("main", "one_of_us:item_especial")
    else
        inv:set_list("main", {})
        inv:add_item("main", "one_of_us:item_especial")
    end
end

function quitar_item_jugador(player)
    local inv = player:get_inventory()
    local items = inv:get_list("main")
    
    for i, stack in ipairs(items) do
        if stack:get_name() == "one_of_us:item_especial" then
            inv:set_stack("main", i, nil)
            return true
        end
    end
    return false
end

minetest.register_allow_player_inventory_action(function(player, action, inventory, inventory_info)
    if action == "put" or action == "move" then
        local stack = action == "put" and inventory_info.stack or inventory_info.from_stack
        if stack:get_name() == "one_of_us:item_especial" then
            return 0 
        end
    end
    return 1
end)

minetest.register_on_punchplayer(function(player, hitter, time_from_last_punch, tool_capabilities, dir, damage)
    if hitter and hitter:is_player() then
        local item_mano = hitter:get_wielded_item():get_name()
        if item_mano == "" then
            return 0 
        end
    end
    return damage
end)


----------------------
local death_ghost_entity = {
    physical = false, 
    collisionbox = {-0.2, -0.2, -0.2, 0.2, 0.2, 0.2},
    visual = "mesh", 
    mesh = "cuerpo.b3d", 
    textures = {"character.png"}, 
    visual_size = {x=1, y=1},
    pointable = false,
    walkable = false,
}

minetest.register_entity("one_of_us:cuerpo", death_ghost_entity)


local active_cadavers = {}

function cadaver(pos, player_name)
    local ghost_entity = minetest.add_entity(pos, "one_of_us:cuerpo")
    if ghost_entity then
        table.insert(active_cadavers, ghost_entity)
        minetest.after(300, function()
            if ghost_entity and ghost_entity:get_pos() then
                ghost_entity:remove()
                for i, v in ipairs(active_cadavers) do
                    if v == ghost_entity then
                        table.remove(active_cadavers, i)
                        break
                    end
                end
            end
        end)
        return ghost_entity
    end
end

function quitar_cadaver()
    for _, entity in ipairs(active_cadavers) do
        if entity and entity:get_pos() then 
            entity:remove()
        end
    end
    active_cadavers = {}
end


function music(player)

    minetest.sound_play({
        name = "theme", 
        gain = 1.0, 
        loop = true 
    }, {
        to_player = player:get_player_name()
    })
end

function dar_priv()
    for _, player in ipairs(core.get_connected_players()) do
        local name = player:get_player_name()
        core.set_player_privs(name, {shout = true, interact = true})
    end
end
function quitar_priv(player)
    local player_name = player:get_player_name()
    core.change_player_privs(player_name, {shout = false, interact = false})
end

minetest.register_globalstep(function(dtime)
    minetest.set_timeofday(0.3)
end)