-- Simple HTTP client for Dota 2 to communicate with Rust RPC server

local Logger = require("libraries/logger")
local HTTPClient = {}

-- Configuration
HTTPClient.SERVER_URL = "http://localhost:5000"
HTTPClient.DEBUG = true

function HTTPClient.Init()
    Logger.info("HTTP_CLIENT", "Initializing HTTP Client")
    Logger.info("HTTP_CLIENT", "Server URL: " .. HTTPClient.SERVER_URL)
end

-- Generic HTTP request function
local function handle_response(request, callback)
    request:Send(function(response)
        if HTTPClient.DEBUG then
            Logger.info("HTTP_CLIENT", "Response status: " .. tostring(response.StatusCode))
        end
        if response.StatusCode == 200 then
            if response.Body and response.Body ~= "" then
                local success, result = pcall(json.decode, response.Body)
                if success then
                    if HTTPClient.DEBUG then
                        Logger.info("HTTP_CLIENT", "Response body: " .. response.Body)
                    end
                    if callback then
                        callback(true, result, response)
                    end
                    return
                else
                    Logger.warn("HTTP_CLIENT", "Error parsing JSON response")
                    if callback then
                        callback(false, "JSON parse error", response)
                    end
                    return
                end
            end
            if callback then
                callback(true, nil, response)
            end
        else
            if HTTPClient.DEBUG then
                Logger.warn("HTTP_CLIENT", "Request failed with status: " .. tostring(response.StatusCode))
            end
            if callback then
                callback(false, "HTTP " .. tostring(response.StatusCode), response)
            end
        end
    end)
end

function HTTPClient.SendRequest(endpoint, data, callback)
    local url = HTTPClient.SERVER_URL .. endpoint
    if HTTPClient.DEBUG then
        Logger.info("HTTP_CLIENT", "Sending request to: " .. url)
        if data then
            Logger.info("HTTP_CLIENT", "Data: " .. json.encode(data))
        end
    end
    local request = CreateHTTPRequestScriptVM("POST", url)
    -- Set headers
    request:SetHTTPRequestHeaderValue("Content-Type", "application/json")
    -- Set body if data provided
    if data then
        local jsonData = json.encode(data)
        request:SetHTTPRequestRawPostBody("application/json", jsonData)
    end
    handle_response(request, callback)
end

function HTTPClient.Get(endpoint, callback)
    local url = HTTPClient.SERVER_URL .. endpoint
    if HTTPClient.DEBUG then
        Logger.info("HTTP_CLIENT", "GET request to: " .. url)
    end
    local request = CreateHTTPRequestScriptVM("GET", url)
    handle_response(request, callback)
end

-- Convenience methods for specific endpoints
function HTTPClient.Ping(callback)
    Logger.info("HTTP_CLIENT", "Sending ping...")
    HTTPClient.SendRequest("/ping", {message = "ping"}, function(success, data)
        if success then
            Logger.info("HTTP_CLIENT", "Ping response: " .. data.message)
        end
        if callback then callback(success, data) end
    end)
end

function HTTPClient.SendEvent(eventType, eventData, callback)
    local payload = {
        event_type = eventType,
        game_time = GameRules:GetDOTATime(false, false),
        timestamp = GetSystemTime()
    }
    -- Merge event data
    for k, v in pairs(eventData or {}) do
        payload[k] = v
    end
    Logger.info("HTTP_CLIENT", "Sending event: " .. eventType)
    HTTPClient.SendRequest("/event", payload, callback)
end

function HTTPClient.NotifyGameStart()
    HTTPClient.SendEvent("game_started", {
        map_name = GetMapName(),
        game_mode = "hello_world"  -- Fixed: just use a string instead of GetClassName
    }, function(success, data)
        if success then
            Logger.info("HTTP_CLIENT", "Game start acknowledged by server")
            if data.server_message then
                Logger.info("HTTP_CLIENT", "Server says: " .. data.server_message)
            end
        end
    end)
end

function HTTPClient.NotifyPlayerConnected(playerID)
    local player = PlayerResource:GetPlayer(playerID)
    if not player then return end
    HTTPClient.SendEvent("player_connected", {
        player_id = playerID,
        player_name = PlayerResource:GetPlayerName(playerID),
        steam_id = tostring(PlayerResource:GetSteamID(playerID))
    }, function(success, data)
        if success then
            Logger.info("HTTP_CLIENT", "Player connection acknowledged")
            -- Check if server sent bonus gold
            if data.bonus_gold and data.bonus_gold > 0 then
                local hero = PlayerResource:GetSelectedHeroEntity(playerID)
                if hero then
                    hero:ModifyGold(data.bonus_gold, false, 0)
                    Logger.info("HTTP_CLIENT", "Bonus gold given: " .. data.bonus_gold)
                end
            end
        end
    end)
end

function HTTPClient.SendHelloWorld(playerID)
    HTTPClient.SendEvent("hello_world", {
        player_id = playerID,
        message = "Hello from Dota 2!"
    }, function(success, data)
        if success then
            Logger.info("HTTP_CLIENT", "Hello World response: " .. (data.message or "No message"))
        end
    end)
end

-- JSON encoding/decoding helpers
-- Dota 2 doesn't have built-in JSON, so we need a simple implementation
local json = {}

function json.encode(tbl)
    if type(tbl) ~= "table" then
        if type(tbl) == "string" then
            return '"' .. tbl:gsub('"', '\\"') .. '"'
        else
            return tostring(tbl)
        end
    end
    local result = {}
    local is_array = #tbl > 0
    if is_array then
        for i, v in ipairs(tbl) do
            table.insert(result, json.encode(v))
        end
        return "[" .. table.concat(result, ",") .. "]"
    else
        for k, v in pairs(tbl) do
            local key = '"' .. tostring(k) .. '"'
            local value = json.encode(v)
            table.insert(result, key .. ":" .. value)
        end
        return "{" .. table.concat(result, ",") .. "}"
    end
end

function json.decode(str)
    -- Simple JSON decoder (handles basic cases)
    -- For production, use a proper JSON library
    local function decode_value(s, pos)
        pos = pos or 1
        -- Skip whitespace
        while pos <= #s and s:sub(pos, pos):match("%s") do
            pos = pos + 1
        end
        if pos > #s then
            return nil, pos
        end
        local char = s:sub(pos, pos)
        -- Object
        if char == "{" then
            local obj = {}
            pos = pos + 1
            while pos <= #s do
                -- Skip whitespace
                while pos <= #s and s:sub(pos, pos):match("%s") do
                    pos = pos + 1
                end
                -- Check for empty object or end
                if s:sub(pos, pos) == "}" then
                    return obj, pos + 1
                end
                -- Parse key (expecting string)
                if s:sub(pos, pos) ~= '"' then
                    error("Expected string key at position " .. pos)
                end
                local key_end = s:find('"', pos + 1)
                local key = s:sub(pos + 1, key_end - 1)
                pos = key_end + 1
                -- Skip whitespace and colon
                while pos <= #s and (s:sub(pos, pos):match("%s") or s:sub(pos, pos) == ":") do
                    pos = pos + 1
                end
                -- Parse value
                local value
                value, pos = decode_value(s, pos)
                obj[key] = value
                -- Skip whitespace
                while pos <= #s and s:sub(pos, pos):match("%s") do
                    pos = pos + 1
                end
                -- Check for comma or end
                if s:sub(pos, pos) == "," then
                    pos = pos + 1
                elseif s:sub(pos, pos) == "}" then
                    return obj, pos + 1
                end
            end
        -- String
        elseif char == '"' then
            local str_end = s:find('"', pos + 1)
            local str = s:sub(pos + 1, str_end - 1)
            return str, str_end + 1
        -- Number
        elseif char:match("[%d%-]") then
            local num_end = pos
            while num_end <= #s and s:sub(num_end, num_end):match("[%d%.%-]") do
                num_end = num_end + 1
            end
            local num = tonumber(s:sub(pos, num_end - 1))
            return num, num_end
        -- Boolean/null
        elseif s:sub(pos, pos + 3) == "true" then
            return true, pos + 4
        elseif s:sub(pos, pos + 4) == "false" then
            return false, pos + 5
        elseif s:sub(pos, pos + 3) == "null" then
            return nil, pos + 4
        end
        error("Unexpected character at position " .. pos .. ": " .. char)
    end
    local result, _ = decode_value(str)
    return result
end

-- Initialize HTTPClient
HTTPClient.json = json

HTTPClient.Init()
_G.HTTPClient = HTTPClient
return HTTPClient
