local PLUGIN = PLUGIN

util.AddNetworkString("ixServerLogs_Request")
util.AddNetworkString("ixServerLogs_Response")
util.AddNetworkString("ixServerLogs_Clear")
util.AddNetworkString("ixServerLogs_OpenMenu")

-- Функция проверки доступа к логам через CAMI
local function HasLogAccess(client)    
    return AdminPrivs[client:GetUserGroup()]
end

-- Инициализация системы логов
function PLUGIN:InitializeLogSystem()
    self.logs = self.logs or {}
    self.logFile = nil
    
    -- Создаем папку для логов
    if ix.config.Get("logSaveToFile", true) then
        local logPath = ix.config.Get("logFilePath", "helix_logs")
        if not file.Exists(logPath, "DATA") then
            file.CreateDir(logPath)
        end
        
        -- Создаем файл для текущей сессии
        local date = os.date("%Y-%m-%d_%H-%M-%S")
        self.logFile = logPath .. "/log_" .. date .. ".txt"
        
        file.Write(self.logFile, "=== Server Logs Started: " .. os.date("%Y-%m-%d %H:%M:%S") .. " ===\n")
    end
end

-- Добавление лога
function PLUGIN:AddLog(logType, message, target, data)
    if not self.LOG_TYPES[logType] then
        print("[ServerLogs] Unknown log type: " .. tostring(logType))
        return
    end
    
    local logEntry = {
        id = #self.logs + 1,
        type = logType,
        category = self.LOG_TYPES[logType].category,
        message = message,
        target = target and {
            name = IsValid(target) and target:Nick() or tostring(target),
            steamid = IsValid(target) and target:SteamID() or "N/A"
        } or nil,
        data = data or {},
        timestamp = os.time(),
        timeString = os.date("%H:%M:%S")
    }
    
    table.insert(self.logs, logEntry)
    
    -- Ограничиваем количество логов в памяти
    local maxEntries = ix.config.Get("logMaxEntries", 1000)
    if #self.logs > maxEntries then
        table.remove(self.logs, 1)
    end
    
    -- Сохраняем в файл
    if self.logFile then
        local logString = string.format("[%s][%s] %s\n", 
            logEntry.timeString,
            self.LOG_CATEGORIES[logEntry.category].name,
            message
        )
        file.Append(self.logFile, logString)
    end
    
    -- Выводим в консоль
    MsgC(self.LOG_CATEGORIES[logEntry.category].color, "[LOG] ", Color(255, 255, 255), message .. "\n")
end

-- Получение логов с фильтрацией
function PLUGIN:GetLogs(filters)
    filters = filters or {}
    local result = {}
    
    for i = #self.logs, 1, -1 do
        local log = self.logs[i]
        local match = true
        
        -- Фильтр по категории
        if filters.category and log.category ~= filters.category then
            match = false
        end
        
        -- Фильтр по типу
        if filters.type and log.type ~= filters.type then
            match = false
        end
        
        -- Фильтр по игроку
        if filters.player and log.target and log.target.steamid ~= filters.player then
            match = false
        end
        
        -- Фильтр по времени
        if filters.startTime and log.timestamp < filters.startTime then
            match = false
        end
        
        if filters.endTime and log.timestamp > filters.endTime then
            match = false
        end
        
        -- Фильтр по тексту
        if filters.search and not string.find(string.lower(log.message), string.lower(filters.search)) then
            match = false
        end
        
        if match then
            table.insert(result, log)
            
            -- Ограничиваем количество результатов
            if filters.limit and #result >= filters.limit then
                break
            end
        end
    end
    
    return result
end

-- Сетевая обработка запроса логов
net.Receive("ixServerLogs_Request", function(len, client)
    if not HasLogAccess(client) then return end
    
    local filters = net.ReadTable()
    local logs = PLUGIN:GetLogs(filters)
    
    -- Отправляем логи порциями
    local chunkSize = 50
    for i = 1, #logs, chunkSize do
        local chunk = {}
        for j = i, math.min(i + chunkSize - 1, #logs) do
            table.insert(chunk, logs[j])
        end
        
        net.Start("ixServerLogs_Response")
            net.WriteUInt(i == 1 and 1 or 0, 2) -- Первый пакет или нет
            net.WriteTable(chunk)
        net.Send(client)
    end
    
    -- Отправляем финальный пакет если логов нет
    if #logs == 0 then
        net.Start("ixServerLogs_Response")
            net.WriteUInt(1, 2)
            net.WriteTable({})
        net.Send(client)
    end
end)

-- Очистка логов
net.Receive("ixServerLogs_Clear", function(len, client)
    if not client:IsSuperAdmin() then return end
    
    PLUGIN.logs = {}
    PLUGIN:AddLog("ADMIN_COMMAND", client:Nick() .. " очистил логи сервера", client)
end)

-- ======================
-- ХУКИ ДЛЯ ЛОГИРОВАНИЯ
-- ======================

-- Смерть игрока
function PLUGIN:PlayerDeath(victim, inflictor, attacker)
    local attackerName = "Мир"
    local attackerSteamID = "world"
    local weapon = "unknown"

    if IsValid(attacker) and attacker:IsPlayer() then
        attackerName = attacker:Nick()
        attackerSteamID = attacker:SteamID()
        weapon = IsValid(attacker:GetActiveWeapon()) and attacker:GetActiveWeapon():GetClass() or "unknown"
    end

    local message = ""

    if IsValid(attacker) and attacker:IsPlayer() then
        if attacker == victim then
            message = victim:Nick() .. " покончил с собой"
        else
            message = attackerName .. " убил " .. victim:Nick() .. " используя " .. weapon
        end
    else
        message = victim:Nick() .. " умер"
    end

    self:AddLog("PLAYER_DEATH", message, victim, {
        attacker = attackerSteamID,
        weapon = weapon
    })
end

-- Получение урона
function PLUGIN:PlayerHurt(victim, attacker, health, damage)
    if not IsValid(attacker) or not attacker:IsPlayer() or attacker == victim then return end
    
    local message = string.format("%s нанёс %d урона игроку %s (осталось %d HP)", 
        attacker:Nick(), damage, victim:Nick(), health)
    
    self:AddLog("PLAYER_HURT", message, victim, {
        attacker = attacker:SteamID(),
        damage = damage,
        health = health
    })
end

-- Подключение игрока
function PLUGIN:PlayerInitialSpawn(client)
    local message = string.format("%s подключился к серверу (SteamID: %s)", 
        client:Nick(), client:SteamID())
    
    self:AddLog("PLAYER_CONNECT", message, client)
end

-- Отключение игрока
function PLUGIN:PlayerDisconnected(client)
    local message = string.format("%s отключился от сервера", client:Nick())
    
    self:AddLog("PLAYER_DISCONNECT", message, client)
end

-- Спавн игрока
function PLUGIN:PlayerSpawn(client)
    if not client:GetCharacter() then return end
    
    local message = string.format("%s заспавнился", client:Nick())
    
    self:AddLog("PLAYER_SPAWN", message, client)
end

-- Сообщения в чат
function PLUGIN:PlayerSay(client, text, teamChat)
    local chatType = teamChat and "[TEAM]" or "[ALL]"
    local message = string.format("%s %s: %s", chatType, client:Nick(), text)
    
    self:AddLog("CHAT_MESSAGE", message, client, {
        text = text,
        team = teamChat
    })
end

-- Создание персонажа
function PLUGIN:OnCharacterCreated(client, character)
    local message = string.format("%s создал персонажа '%s'", 
        client:Nick(), character:GetName())
    
    self:AddLog("CHARACTER_CREATE", message, client, {
        characterID = character:GetID(),
        characterName = character:GetName()
    })
end

-- Удаление персонажа
function PLUGIN:PreCharacterDeleted(client, character)
    local message = string.format("%s удалил персонажа '%s'", 
        client:Nick(), character:GetName())
    
    self:AddLog("CHARACTER_DELETE", message, client, {
        characterID = character:GetID(),
        characterName = character:GetName()
    })
end

-- Смена персонажа
function PLUGIN:PlayerLoadedCharacter(client, character, oldCharacter)
    if oldCharacter then
        local message = string.format("%s сменил персонажа с '%s' на '%s'", 
            client:Nick(), oldCharacter:GetName(), character:GetName())
        
        self:AddLog("CHARACTER_SWITCH", message, client, {
            oldCharacter = oldCharacter:GetName(),
            newCharacter = character:GetName()
        })
    end
end

-- Покупка предмета
function PLUGIN:CharacterVendorTraded(client, vendor, x, y, invID, price, isSell)
    local action = isSell and "продал" or "купил"
    local message = string.format("%s %s предмет за %d", 
        client:Nick(), action, price)
    
    self:AddLog("ITEM_PURCHASE", message, client, {
        vendor = vendor,
        price = price,
        sell = isSell
    })
end

-- Использование предмета
function PLUGIN:OnItemTransferred(item, curInv, inventory)
    if item.player then
        local message = string.format("%s переместил предмет '%s'", 
            item.player:Nick(), item:GetName())
        
        self:AddLog("INVENTORY", message, item.player, {
            item = item:GetName(),
            itemID = item:GetID()
        })
    end
end

-- Инициализация при загрузке плагина
function PLUGIN:InitPostEntity()
    self:InitializeLogSystem()
    self:AddLog("ADMIN_COMMAND", "Система логов инициализирована")
end

-- ======================
-- КОМАНДЫ HELIX
-- ======================

-- Регистрация CAMI разрешения
if CAMI then
    CAMI.RegisterPrivilege({
        Name = "Helix - View Server Logs",
        MinAccess = "admin",
        Description = "Позволяет просматривать логи сервера"
    })
    
    CAMI.RegisterPrivilege({
        Name = "Helix - Clear Server Logs",
        MinAccess = "superadmin",
        Description = "Позволяет очищать логи сервера"
    })
    
    CAMI.RegisterPrivilege({
        Name = "Helix - Use Handcuffs",
        MinAccess = "admin",
        Description = "Позволяет использовать наручники"
    })
end

-- Команда для просмотра логов
ix.command.Add("ViewLogs", {
    description = "Открыть панель просмотра логов сервера",
    OnCheckAccess = function(self, client)
        return HasLogAccess(client)
    end,
    OnRun = function(self, client)
        -- Отправляем команду на открытие меню на клиенте
        net.Start("ixServerLogs_OpenMenu")
        net.Send(client)
        
        return "@serverLogsOpened"
    end
})

-- Альтернативная команда
ix.command.Add("ServerLogs", {
    description = "Открыть панель просмотра логов сервера",
    OnCheckAccess = function(self, client)
        return HasLogAccess(client)
    end,
    OnRun = function(self, client)
        -- Отправляем команду на открытие меню на клиенте
        net.Start("ixServerLogs_OpenMenu")
        net.Send(client)
        
        return "@serverLogsOpened"
    end
})

-- Команда для очистки логов
ix.command.Add("ClearLogs", {
    description = "Очистить все логи сервера",
    superAdminOnly = true,
    OnCheckAccess = function(self, client)
        -- Проверка через CAMI
        if CAMI then
            return CAMI.PlayerHasAccess(client, "Helix - Clear Server Logs", function(allowed)
                return allowed
            end)
        end
        -- Fallback на стандартную проверку суперадмина
        return client:IsSuperAdmin()
    end,
    OnRun = function(self, client)
        PLUGIN.logs = {}
        PLUGIN:AddLog("ADMIN_COMMAND", client:Nick() .. " очистил логи сервера", client)
        return "@serverLogsCleared"
    end
})

-- Команда для просмотра последних логов в консоли
ix.command.Add("LastLogs", {
    description = "Показать последние 20 логов в консоли",
    adminOnly = true,
    arguments = {
        ix.type.number,
    },
    argumentNames = {"количество"},
    OnCheckAccess = function(self, client)
        -- Проверка через CAMI
        if CAMI then
            return CAMI.PlayerHasAccess(client, "Helix - View Server Logs", function(allowed)
                return allowed
            end)
        end
        return client:IsAdmin()
    end,
    OnRun = function(self, client, count)
        count = math.Clamp(count or 20, 1, 100)
        
        local logs = PLUGIN:GetLogs({limit = count})
        
        client:ChatPrint("=== Последние " .. #logs .. " логов ===")
        for i, log in ipairs(logs) do
            local categoryName = PLUGIN.LOG_CATEGORIES[log.category].name
            local targetInfo = log.target and (" [" .. log.target.name .. "]") or ""
            client:ChatPrint(string.format("[%s][%s]%s %s", 
                log.timeString, categoryName, targetInfo, log.message))
        end
        
        return "@serverLogsDisplayed", #logs
    end
})

-- Команда для поиска в логах
ix.command.Add("SearchLogs", {
    description = "Найти логи по тексту или игроку",
    adminOnly = true,
    arguments = {
        ix.type.text,
    },
    argumentNames = {"поисковый запрос"},
    OnCheckAccess = function(self, client)
        -- Проверка через CAMI
        if CAMI then
            return CAMI.PlayerHasAccess(client, "Helix - View Server Logs", function(allowed)
                return allowed
            end)
        end
        return client:IsAdmin()
    end,
    OnRun = function(self, client, search)
        local logs = PLUGIN:GetLogs({search = search, limit = 50})
        
        client:ChatPrint("=== Найдено логов: " .. #logs .. " ===")
        for i, log in ipairs(logs) do
            local categoryName = PLUGIN.LOG_CATEGORIES[log.category].name
            local targetInfo = log.target and (" [" .. log.target.name .. "]") or ""
            client:ChatPrint(string.format("[%s][%s]%s %s", 
                log.timeString, categoryName, targetInfo, log.message))
        end
        
        return "@serverLogsSearchResults", #logs
    end
})
