local PLUGIN = PLUGIN
-- Таблица активных отрядов
PLUGIN.squads = PLUGIN.squads or {}
PLUGIN.playerSquads = PLUGIN.playerSquads or {} -- [SteamID] = squadID
PLUGIN.squadInvites = PLUGIN.squadInvites or {} -- [SteamID] = {squadID, inviterSteamID}

util.AddNetworkString("ixSquadCreate")
util.AddNetworkString("ixSquadDisband")
util.AddNetworkString("ixSquadInvite")
util.AddNetworkString("ixSquadAcceptInvite")
util.AddNetworkString("ixSquadDeclineInvite")
util.AddNetworkString("ixSquadKick")
util.AddNetworkString("ixSquadLeave")
util.AddNetworkString("ixSquadPromote")
util.AddNetworkString("ixSquadSync")
util.AddNetworkString("ixSquadNotify")
util.AddNetworkString("ixSquadUpdateMarkers")
util.AddNetworkString("ixSquadPlaceMarker")
util.AddNetworkString("ixSquadWorldMarker")


local function IsAdminMode(ply)
    return ply.GetNetVar and ply:GetNetVar("AdminMode", false)
end
-- Генерация уникального ID отряда
function PLUGIN:GenerateSquadID()
    local id
    repeat
        id = "squad_" .. os.time() .. "_" .. math.random(1000, 9999)
    until not self.squads[id]
    return id
end

-- Получить отряд игрока
function PLUGIN:GetPlayerSquad(client)
    local steamID = client:SteamID()
    local squadID = self.playerSquads[steamID]
    if squadID then
        return self.squads[squadID], squadID
    end
    return nil, nil
end

-- Получить фракцию игрока
function PLUGIN:GetPlayerFaction(client)
    local character = client:GetCharacter()
    if not character then return nil end
    return character:GetFaction()
end

-- Создание отряда
function PLUGIN:CreateSquad(leader)

    if IsAdminMode(leader) then
        return false, "Администратор не может создавать отряд"
    end
    
    if not IsValid(leader) then 
        return false, "Недействительный игрок" 
    end
    
    local steamID = leader:SteamID()
    
    -- Проверяем, не состоит ли уже в отряде
    if self.playerSquads[steamID] then
        return false, "Вы уже состоите в отряде"
    end
    
    local faction = self:GetPlayerFaction(leader)
    
    if not faction then
        return false, "У вас нет активного персонажа"
    end
    
    local squadID = self:GenerateSquadID()
    
    self.squads[squadID] = {
        id = squadID,
        leader = steamID,
        faction = faction,
        members = {steamID},
        memberData = {
            [steamID] = {
                name = leader:Name(),
                isLeader = true,
                joinTime = os.time()
            }
        },
        createdAt = os.time()
    }
    
    self.playerSquads[steamID] = squadID
    
    self:SyncSquadToMembers(squadID)
    self:StartSquadMarkers(squadID)
    
    -- Логирование создания отряда
    local serverlogsPlugin = ix.plugin.list["serverlogs"]
    if (serverlogsPlugin) then
        local factionName = ix.faction.Get(faction).name or tostring(faction)
        local message = string.format("%s создал отряд (ID: %s, фракция: %s)", leader:Nick(), squadID, factionName)
        serverlogsPlugin:AddLog("SQUAD_CREATE", message, leader, {
            squadID = squadID,
            faction = faction,
            factionName = factionName
        })
    end
    
    return true, "Отряд успешно создан"
end

-- Расформирование отряда
function PLUGIN:DisbandSquad(squadID)
    local squad = self.squads[squadID]
    if not squad then return false, "Отряд не найден" end
    
    -- Логируем расформирование перед удалением
    local serverlogsPlugin = ix.plugin.list["serverlogs"]
    if (serverlogsPlugin) then
        local leaderName = squad.memberData[squad.leader] and squad.memberData[squad.leader].name or "Unknown"
        local factionName = ix.faction.Get(squad.faction).name or tostring(squad.faction)
        local message = string.format("Отряд %s расформирован (лидер: %s, членов: %d, фракция: %s)", 
            squadID, leaderName, #squad.members, factionName)
        serverlogsPlugin:AddLog("SQUAD_DELETE", message, nil, {
            squadID = squadID,
            leader = squad.leader,
            leaderName = leaderName,
            memberCount = #squad.members,
            faction = squad.faction,
            factionName = factionName
        })
    end
    
    -- Останавливаем маркеры
    self:StopSquadMarkers(squadID)
    
    -- Очищаем данные на клиенте и уведомляем всех членов
    for _, memberSteamID in ipairs(squad.members) do
        local member = player.GetBySteamID(memberSteamID)
        if IsValid(member) then
            -- Отправляем пустую таблицу для очистки данных на клиенте
            net.Start("ixSquadSync")
                net.WriteString("{}")
            net.Send(member)
            
            net.Start("ixSquadNotify")
                net.WriteString("Отряд был расформирован")
            net.Send(member)
        end
        self.playerSquads[memberSteamID] = nil
    end
    
    self.squads[squadID] = nil
    
    return true, "Отряд расформирован"
end

-- Приглашение в отряд
function PLUGIN:InviteToSquad(inviter, target)
    print("[SQUADS] InviteToSquad вызван: inviter=" .. (IsValid(inviter) and inviter:Name() or "NIL") .. ", target=" .. (IsValid(target) and target:Name() or "NIL"))

    if IsAdminMode(inviter) then
        return false, "Администратор не может приглашать в отряд"
    end

    if not IsValid(inviter) or not IsValid(target) then
        print("[SQUADS] Ошибка: недействительный игрок")
        return false, "Недействительный игрок"
    end
    
    local squad, squadID = self:GetPlayerSquad(inviter)
    if not squad then
        print("[SQUADS] Ошибка: инвайтер не в отряде")
        return false, "Вы не состоите в отряде"
    end
    
    print("[SQUADS] Отряд найден: " .. squadID)
    
    local inviterSteamID = inviter:SteamID()
    if squad.leader ~= inviterSteamID then
        print("[SQUADS] Ошибка: не лидер (leader=" .. squad.leader .. ", inviter=" .. inviterSteamID .. ")")
        return false, "Только лидер может приглашать игроков"
    end
    
    local targetSteamID = target:SteamID()
    
    -- Проверяем, не состоит ли уже в отряде
    if self.playerSquads[targetSteamID] then
        print("[SQUADS] Ошибка: target уже в отряде")
        return false, target:Name() .. " уже состоит в отряде"
    end
    
    -- Проверяем лимит
    if #squad.members >= ix.config.Get("squadMaxMembers", 16) then
        print("[SQUADS] Ошибка: отряд заполнен")
        return false, "Отряд заполнен (макс. " .. ix.config.Get("squadMaxMembers", 16) .. " человек)"
    end
    
    -- Проверяем фракцию
    local targetFaction = self:GetPlayerFaction(target)
    if targetFaction ~= squad.faction then
        print("[SQUADS] Ошибка: разные фракции (squad=" .. squad.faction .. ", target=" .. (targetFaction or "NIL") .. ")")
        return false, target:Name() .. " из другой фракции"
    end
    
    -- Проверяем, нет ли уже приглашения
    if self.squadInvites[targetSteamID] then
        print("[SQUADS] Ошибка: у target уже есть приглашение")
        return false, target:Name() .. " уже имеет активное приглашение"
    end
    
    -- Сохраняем приглашение
    self.squadInvites[targetSteamID] = {
        squadID = squadID,
        inviterSteamID = inviterSteamID,
        inviterName = inviter:Name(),
        time = CurTime()
    }
    
    print("[SQUADS] Приглашение сохранено для " .. target:Name())
    
    -- Отправляем приглашение
    net.Start("ixSquadInvite")
        net.WriteString(squadID)
        net.WriteString(inviter:Name())
    net.Send(target)
    
    print("[SQUADS] Приглашение отправлено клиенту " .. target:Name())
    
    -- Уведомляем инвайтера
    net.Start("ixSquadNotify")
        net.WriteString("Приглашение отправлено " .. target:Name())
    net.Send(inviter)
    
    -- Логирование приглашения в отряд
    local serverlogsPlugin = ix.plugin.list["serverlogs"]
    if (serverlogsPlugin) then
        local message = string.format("%s пригласил %s в отряд %s", inviter:Nick(), target:Nick(), squadID)
        serverlogsPlugin:AddLog("SQUAD_INVITE", message, inviter, {
            squadID = squadID,
            targetSteamID = targetSteamID,
            targetName = target:Nick()
        })
    end
    
    -- Автоматическое удаление через 30 секунд
    timer.Simple(30, function()
        if self.squadInvites[targetSteamID] and self.squadInvites[targetSteamID].squadID == squadID then
            self.squadInvites[targetSteamID] = nil
            print("[SQUADS] Приглашение для " .. targetSteamID .. " истекло")
        end
    end)
    
    return true, "Приглашение отправлено"
end

-- Принятие приглашения
function PLUGIN:AcceptSquadInvite(client)
    local steamID = client:SteamID()
    local invite = self.squadInvites[steamID]

    if IsAdminMode(client) then
        return false, "Администратор не может вступать в отряд"
    end
    
    if not invite then
        return false, "У вас нет активных приглашений"
    end
    
    local squad = self.squads[invite.squadID]
    if not squad then
        self.squadInvites[steamID] = nil
        return false, "Отряд больше не существует"
    end
    
    -- Проверяем лимит еще раз
    if #squad.members >= ix.config.Get("squadMaxMembers", 16) then
        self.squadInvites[steamID] = nil
        return false, "Отряд уже заполнен"
    end
    
    -- Проверяем фракцию еще раз (на случай смены персонажа)
    local currentFaction = self:GetPlayerFaction(client)
    if currentFaction ~= squad.faction then
        self.squadInvites[steamID] = nil
        return false, "Вы больше не в той же фракции"
    end
    
    -- Добавляем в отряд
    table.insert(squad.members, steamID)
    squad.memberData[steamID] = {
        name = client:Name(),
        isLeader = false,
        joinTime = os.time()
    }
    
    self.playerSquads[steamID] = invite.squadID
    self.squadInvites[steamID] = nil
    
    -- Уведомляем всех членов отряда
    for _, memberSteamID in ipairs(squad.members) do
        local member = player.GetBySteamID(memberSteamID)
        if IsValid(member) then
            net.Start("ixSquadNotify")
                net.WriteString(client:Name() .. " присоединился к отряду")
            net.Send(member)
        end
    end
    
    self:SyncSquadToMembers(invite.squadID)
    
    -- Логирование вступления в отряд
    local serverlogsPlugin = ix.plugin.list["serverlogs"]
    if (serverlogsPlugin) then
        local factionName = ix.faction.Get(squad.faction).name or tostring(squad.faction)
        local message = string.format("%s присоединился к отряду %s (лидер: %s)", 
            client:Nick(), invite.squadID, squad.memberData[squad.leader].name)
        serverlogsPlugin:AddLog("SQUAD_JOIN", message, client, {
            squadID = invite.squadID,
            inviterSteamID = invite.inviterSteamID,
            inviterName = invite.inviterName,
            faction = squad.faction,
            factionName = factionName
        })
    end
    
    return true, "Вы присоединились к отряду"
end

-- Исключение из отряда
function PLUGIN:KickFromSquad(kicker, targetSteamID)
    if not IsValid(kicker) then return false, "Недействительный игрок" end
    
    local squad, squadID = self:GetPlayerSquad(kicker)
    if not squad then
        return false, "Вы не состоите в отряде"
    end
    
    if squad.leader ~= kicker:SteamID() then
        return false, "Только лидер может исключать игроков"
    end
    
    if targetSteamID == kicker:SteamID() then
        return false, "Используйте расформирование отряда"
    end
    
    -- Удаляем из отряда
    for i, memberSteamID in ipairs(squad.members) do
        if memberSteamID == targetSteamID then
            table.remove(squad.members, i)
            break
        end
    end
    
    local targetName = squad.memberData[targetSteamID].name
    squad.memberData[targetSteamID] = nil
    self.playerSquads[targetSteamID] = nil
    
    -- Уведомляем исключенного игрока и очищаем его данные
    local target = player.GetBySteamID(targetSteamID)
    if IsValid(target) then
        -- Очищаем данные отряда на клиенте
        net.Start("ixSquadSync")
            net.WriteString("{}")
        net.Send(target)
        
        net.Start("ixSquadNotify")
            net.WriteString("Вы были исключены из отряда")
        net.Send(target)
    end
    
    -- Уведомляем остальных
    for _, memberSteamID in ipairs(squad.members) do
        local member = player.GetBySteamID(memberSteamID)
        if IsValid(member) then
            net.Start("ixSquadNotify")
                net.WriteString(targetName .. " был исключен из отряда")
            net.Send(member)
        end
    end
    
    self:SyncSquadToMembers(squadID)
    
    -- Логирование исключения из отряда
    local serverlogsPlugin = ix.plugin.list["serverlogs"]
    if (serverlogsPlugin) then
        local message = string.format("%s исключил %s из отряда %s", kicker:Nick(), targetName, squadID)
        serverlogsPlugin:AddLog("SQUAD_KICK", message, kicker, {
            squadID = squadID,
            targetSteamID = targetSteamID,
            targetName = targetName
        })
    end
    
    return true, targetName .. " исключен из отряда"
end

-- Выход из отряда
function PLUGIN:LeaveSquad(client)
    local squad, squadID = self:GetPlayerSquad(client)
    if not squad then
        return false, "Вы не состоите в отряде"
    end
    
    local steamID = client:SteamID()
    
    -- Если лидер - расформировываем отряд
    if squad.leader == steamID then
        return self:DisbandSquad(squadID)
    end
    
    -- Удаляем из отряда
    for i, memberSteamID in ipairs(squad.members) do
        if memberSteamID == steamID then
            table.remove(squad.members, i)
            break
        end
    end
    
    squad.memberData[steamID] = nil
    self.playerSquads[steamID] = nil
    
    -- Уведомляем остальных
    for _, memberSteamID in ipairs(squad.members) do
        local member = player.GetBySteamID(memberSteamID)
        if IsValid(member) then
            net.Start("ixSquadNotify")
                net.WriteString(client:Name() .. " покинул отряд")
            net.Send(member)
        end
    end
    
    self:SyncSquadToMembers(squadID)
    
    -- Логирование выхода из отряда
    local serverlogsPlugin = ix.plugin.list["serverlogs"]
    if (serverlogsPlugin) then
        local message = string.format("%s покинул отряд %s", client:Nick(), squadID)
        serverlogsPlugin:AddLog("SQUAD_LEAVE", message, client, {
            squadID = squadID
        })
    end
    
    return true, "Вы покинули отряд"
end

-- Система маркеров на компасе
function PLUGIN:StartSquadMarkers(squadID)
    local timerName = "ixSquadMarkers_" .. squadID
    
    timer.Create(timerName, ix.config.Get("squadMarkerUpdateRate", 0.5), 0, function()
        local squad = self.squads[squadID]
        if not squad then
            timer.Remove(timerName)
            return
        end
        
        -- Обновляем маркеры для каждого члена отряда
        for _, memberSteamID in ipairs(squad.members) do
            local member = player.GetBySteamID(memberSteamID)
            if IsValid(member) then
                -- Получаем других членов отряда
                local teammates = {}
                for _, otherSteamID in ipairs(squad.members) do
                    if otherSteamID ~= memberSteamID then
                        local teammate = player.GetBySteamID(otherSteamID)
                        if IsValid(teammate) and teammate:Alive() then
                            table.insert(teammates, teammate)
                        end
                    end
                end
                
                -- Отправляем позиции союзников этому игроку
                if #teammates > 0 then
                    net.Start("ixSquadUpdateMarkers")
                        net.WriteUInt(#teammates, 8)
                        for _, teammate in ipairs(teammates) do
                            net.WriteVector(teammate:GetPos())
                            net.WriteString(teammate:Name())
                            net.WriteEntity(teammate)
                        end
                    net.Send(member)
                end
            end
        end
    end)
end

function PLUGIN:StopSquadMarkers(squadID)
    timer.Remove("ixSquadMarkers_" .. squadID)
end

-- Синхронизация данных отряда
function PLUGIN:SyncSquadToMembers(squadID)
    local squad = self.squads[squadID]
    if not squad then return end
    
    for _, memberSteamID in ipairs(squad.members) do
        local member = player.GetBySteamID(memberSteamID)
        if IsValid(member) then
            net.Start("ixSquadSync")
                net.WriteString(util.TableToJSON(squad))
            net.Send(member)
        end
    end
end

function PLUGIN:SyncAllSquads()
    for _, client in ipairs(player.GetAll()) do
        local squad, squadID = self:GetPlayerSquad(client)
        if squad then
            net.Start("ixSquadSync")
                net.WriteString(util.TableToJSON(squad))
            net.Send(client)
        end
    end
end

-- Обработка отключения игрока
function PLUGIN:PlayerDisconnected(client)
    if not IsValid(client) then return end
    
    local steamID = client:SteamID()
    local squad, squadID = self:GetPlayerSquad(client)
    
    if squad then
        -- Если это лидер - расформировываем отряд
        if squad.leader == steamID then
            print("[SQUADS] Лидер " .. client:Name() .. " отключился, расформирование отряда " .. squadID)
            self:DisbandSquad(squadID)
        else
            -- Обычный участник - просто покидает отряд
            print("[SQUADS] Игрок " .. client:Name() .. " отключился, удаление из отряда " .. squadID)
            
            -- Удаляем из списка участников
            for i, memberSteamID in ipairs(squad.members) do
                if memberSteamID == steamID then
                    table.remove(squad.members, i)
                    break
                end
            end
            
            squad.memberData[steamID] = nil
            self.playerSquads[steamID] = nil
            
            -- Уведомляем остальных участников
            for _, memberSteamID in ipairs(squad.members) do
                local member = player.GetBySteamID(memberSteamID)
                if IsValid(member) then
                    net.Start("ixSquadNotify")
                        net.WriteString(client:Name() .. " покинул отряд (отключение)")
                    net.Send(member)
                end
            end
            
            -- Синхронизируем данные с оставшимися участниками
            self:SyncSquadToMembers(squadID)
        end
    end
    
    -- Удаляем приглашения
    self.squadInvites[steamID] = nil
end

-- Сетевые обработчики
net.Receive("ixSquadCreate", function(len, client)
    local plugin = ix.plugin.Get("squads")
    if not plugin then 
        return 
    end
    if IsAdminMode(client) then return end
    
    local success, message = plugin:CreateSquad(client)
    
    net.Start("ixSquadNotify")
        net.WriteString(message)
    net.Send(client)
end)

net.Receive("ixSquadDisband", function(len, client)
    local plugin = ix.plugin.Get("squads")
    if not plugin then return end
    if IsAdminMode(client) then return end
  
    local squad, squadID = plugin:GetPlayerSquad(client)
    if squad and squad.leader == client:SteamID() then
        plugin:DisbandSquad(squadID)
    end
end)

net.Receive("ixSquadInvite", function(len, client)
    local plugin = ix.plugin.Get("squads")
    if not plugin then return end
    if IsAdminMode(client) then return end
    
    local targetSteamID = net.ReadString()
    print("[SQUADS SERVER] Получен запрос на приглашение от " .. client:Name() .. " для SteamID: " .. targetSteamID)
    
    local target = player.GetBySteamID(targetSteamID)
    print("[SQUADS SERVER] Найден игрок: " .. (IsValid(target) and target:Name() or "NIL"))
    
    if IsValid(target) then
        local success, message = plugin:InviteToSquad(client, target)
        print("[SQUADS SERVER] Результат приглашения: " .. tostring(success) .. " - " .. message)
        net.Start("ixSquadNotify")
            net.WriteString(message)
        net.Send(client)
    else
        net.Start("ixSquadNotify")
            net.WriteString("Игрок не найден")
        net.Send(client)
    end
end)

net.Receive("ixSquadAcceptInvite", function(len, client)
    local plugin = ix.plugin.Get("squads")
    if not plugin then return end
    if IsAdminMode(client) then return end
  
    local success, message = plugin:AcceptSquadInvite(client)
    net.Start("ixSquadNotify")
        net.WriteString(message)
    net.Send(client)
end)

net.Receive("ixSquadDeclineInvite", function(len, client)
    local plugin = ix.plugin.Get("squads")
    if not plugin then return end
    if IsAdminMode(client) then return end

    local invite = plugin.squadInvites[client:SteamID()]
    
    -- Уведомляем лидера об отклонении
    if invite then
        local inviter = player.GetBySteamID(invite.inviterSteamID)
        if IsValid(inviter) then
            net.Start("ixSquadNotify")
                net.WriteString(client:Name() .. " отклонил приглашение")
            net.Send(inviter)
        end
    end
    
    plugin.squadInvites[client:SteamID()] = nil
    net.Start("ixSquadNotify")
        net.WriteString("Приглашение отклонено")
    net.Send(client)
end)

net.Receive("ixSquadKick", function(len, client)
    local plugin = ix.plugin.Get("squads")
    if not plugin then return end
    if IsAdminMode(client) then return end
    
    local targetSteamID = net.ReadString()
    local success, message = plugin:KickFromSquad(client, targetSteamID)
    net.Start("ixSquadNotify")
        net.WriteString(message)
    net.Send(client)
end)

net.Receive("ixSquadLeave", function(len, client)
    local plugin = ix.plugin.Get("squads")
    if not plugin then return end
    if IsAdminMode(client) then return end
    
    local success, message = plugin:LeaveSquad(client)
    net.Start("ixSquadNotify")
        net.WriteString(message)
    net.Send(client)
end)

net.Receive("ixSquadPlaceMarker", function(len, client)
    local plugin = ix.plugin.Get("squads")
    if not plugin then return end
    if not IsValid(client) or not client:Alive() then return end

    local squad, squadID = plugin:GetPlayerSquad(client)
    if not squad then return end

    local pos = net.ReadVector()
    if not pos then return end

    for _, memberSteamID in ipairs(squad.members) do
        local member = player.GetBySteamID(memberSteamID)
        if IsValid(member) then
            net.Start("ixSquadWorldMarker")
                net.WriteVector(pos)
                net.WriteString(client:Name())
            net.Send(member)
        end
    end
end)
