local obj = {}
obj.__index = obj

-- CONFIGURATION
local PROJECT_ID = "gen-lang-client-0842463959" 
local PROJECT_NAME = "Google API Monitor" 
local menu = hs.menubar.new()
local accessToken = nil

-- Data storage
local history = {} 
local lastMetrics = {
    requests = 0,
    throughput = "0 B",
    errors = 0,
    latency = "0 ms",
    quotaPercent = 0
}

-- Helper: Format bytes
local function formatBytes(bytes)
    if not bytes or bytes == 0 then return "0 B" end
    local units = {"B", "KB", "MB", "GB"}
    local i = 1
    while bytes > 1024 and i < #units do
        bytes = bytes / 1024
        i = i + 1
    end
    return string.format("%.2f %s", bytes, units[i])
end

-- Helper: ASCII Trend Graph (Traffic)
local function getTrendString()
    if #history < 2 then return "▂ Loading..." end
    local bars = {" ", "▂", "▃", "▄", "▅", "▆", "▇", "█"}
    local maxVal = 0
    for _, v in ipairs(history) do if v > maxVal then maxVal = v end end
    local res = ""
    for _, v in ipairs(history) do
        local idx = 1
        if maxVal > 0 then
            idx = math.floor((v / maxVal) * 7) + 1
        end
        res = res .. bars[idx]
    end
    return res
end

-- Helper: Token Refresh
local function refreshAuth(callback)
    local scriptPath = os.getenv("HOME") .. "/.hammerspoon/get_token.py"
    hs.task.new("/usr/bin/python3", function(exitCode, stdOut, stdErr)
        if exitCode == 0 then
            accessToken = stdOut:gsub("%s+", "")
            if callback then callback() end
        else
            print("Python Auth Error: " .. (stdErr or "Unknown"))
        end
    end, {scriptPath}):start()
end

-- Generic Fetch
local function fetchMetric(metricType, callback)
    if not accessToken then return end
    local now = os.date("!%Y-%m-%dT%H:%M:%SZ")
    local start = os.date("!%Y-%m-%dT%H:%M:%SZ", os.time() - 3600)
    local baseUrl = "https://monitoring.googleapis.com/v3/projects/" .. PROJECT_ID .. "/timeSeries"
    
    local fullUrl = baseUrl .. "?" .. 
                    "filter=" .. hs.http.encodeForQuery('metric.type="' .. metricType .. '"') .. 
                    "&interval.startTime=" .. hs.http.encodeForQuery(start) .. 
                    "&interval.endTime=" .. hs.http.encodeForQuery(now)

    hs.http.asyncGet(fullUrl, {Authorization = "Bearer " .. accessToken}, function(status, body)
        if status == 200 then
            local data = hs.json.decode(body)
            local total, count = 0, 0
            if data and data.timeSeries then
                for _, series in ipairs(data.timeSeries) do
                    for _, point in ipairs(series.points or {}) do
                        local val = point.value.int64Value or point.value.doubleValue or 0
                        total = total + tonumber(val)
                        count = count + 1
                    end
                end
            end
            callback(total, count)
        elseif status == 401 or status == 403 then
            accessToken = nil 
        end
    end)
end

function obj.updateMenu()
    local trend = getTrendString()
    local qColor = {white=1}
    if lastMetrics.quotaPercent >= 90 then qColor = {red=1}
    elseif lastMetrics.quotaPercent >= 75 then qColor = {orange=1} end

    menu:setMenu({
        { title = "Project: " .. PROJECT_NAME, disabled = true },
        { title = "Traffic Trend: " .. trend, disabled = true },
        { title = "-" },
        { title = "Quota Utilization: " .. lastMetrics.quotaPercent .. "%", font={color=qColor} },
        { title = "Total Requests (1h): " .. lastMetrics.requests },
        { title = "Average Latency: " .. lastMetrics.latency },
        { title = "Data Throughput: " .. lastMetrics.throughput },
        { title = "Errors (1h): " .. lastMetrics.errors, font = { color = (lastMetrics.errors > 0 and {red=1} or {white=1}) } },
        { title = "-" },
        { title = "Refresh Now", fn = function() obj.updateQuota() end },
        { title = "Open Google Console", fn = function() hs.urlevent.openURL("https://console.cloud.google.com/apis/dashboard?project=" .. PROJECT_ID) end }
    })
end

function obj.updateQuota()
    if not accessToken then
        refreshAuth(function() obj.updateQuota() end)
        return
    end

    -- 1. Fetch Traffic
    fetchMetric("serviceruntime.googleapis.com/api/request_count", function(reqCount)
        lastMetrics.requests = reqCount
        
        -- Update history for trend bars
        table.insert(history, reqCount)
        if #history > 10 then table.remove(history, 1) end

        -- 2. Fetch Quota Usage vs Limit
        fetchMetric("serviceruntime.googleapis.com/quota/allocation/usage", function(usage)
            fetchMetric("serviceruntime.googleapis.com/quota/limit", function(limit)
                lastMetrics.quotaPercent = (limit > 0) and math.floor((usage / limit) * 100) or 0

                -- 3. Fetch Throughput and Latency
                fetchMetric("serviceruntime.googleapis.com/api/response_sizes", function(bytes)
                    lastMetrics.throughput = formatBytes(bytes)
                    fetchMetric("serviceruntime.googleapis.com/api/request_latencies", function(totalLat, count)
                        lastMetrics.latency = count > 0 and string.format("%.2f ms", (totalLat / count) * 1000) or "0 ms"

                        -- 4. Errors
                        local errFilter = 'serviceruntime.googleapis.com/api/request_count" AND metric.labels.response_code_class!="2xx'
                        fetchMetric(errFilter, function(errCount)
                            lastMetrics.errors = errCount
                            
                            -- Title Icon Logic
                            local statusIcon = ""
                            if errCount > 0 then statusIcon = "🔴 "
                            elseif lastMetrics.quotaPercent >= 80 then statusIcon = "⚠️ " 
                            end
                            
                            menu:setTitle(statusIcon .. "G-API: " .. reqCount)
                            obj.updateMenu()
                        end)
                    end)
                end)
            end)
        end)
    end)
end

function obj.init()
    if menu then
        menu:setTitle("G-API: ...")
        obj.updateMenu()
        -- Polling every 5 minutes
        obj.timer = hs.timer.doEvery(300, function() obj.updateQuota() end)
        obj.updateQuota()
    end
end

return obj