--[[
    Commander 3.0 - Headless Test Script

    This file tests the core functionality without any UI.
    Load this file after the main addon to run tests.

    Usage: Add to TOC (at end) or /run loadfile("tests/headless_test.lua")()
]]

local ADDON_NAME, C3 = ...

-- Wait for addon to fully initialize
C3:OnInit(function()
    print("|cFF00FF00[C3 Test]|r Starting headless tests...")

    local passed = 0
    local failed = 0

    local function test(name, fn)
        local ok, result = pcall(fn)
        if ok and result then
            passed = passed + 1
            print("|cFF00FF00[PASS]|r " .. name)
        else
            failed = failed + 1
            print("|cFFFF0000[FAIL]|r " .. name .. ": " .. tostring(result or "returned false"))
        end
    end

    ---------------------------------------------------------------------------
    -- Core Tests
    ---------------------------------------------------------------------------

    test("C3 namespace exists", function()
        return C3 ~= nil and C3.VERSION ~= nil
    end)

    test("Kernel exists", function()
        return C3._kernel ~= nil
    end)

    test("Parser exists", function()
        return C3.Parser ~= nil and C3.Parser.Parse ~= nil
    end)

    test("Pipeline exists", function()
        return C3.Pipeline ~= nil
    end)

    test("Types system exists", function()
        return C3.Types ~= nil and C3.Types.Create ~= nil
    end)

    ---------------------------------------------------------------------------
    -- Lexer Tests
    ---------------------------------------------------------------------------

    test("Lexer tokenizes simple command", function()
        local tokens = C3.Lexer.TokenizeString("echo hello")
        return tokens and #tokens >= 2
    end)

    test("Lexer handles pipes", function()
        local tokens = C3.Lexer.TokenizeString("bags | where quality > 3")
        local hasPipe = false
        for _, t in ipairs(tokens) do
            if t.type == "PIPE" then hasPipe = true end
        end
        return hasPipe
    end)

    test("Lexer handles variables", function()
        local tokens = C3.Lexer.TokenizeString("echo $player")
        local hasVar = false
        for _, t in ipairs(tokens) do
            if t.type == "VARIABLE" then hasVar = true end
        end
        return hasVar
    end)

    ---------------------------------------------------------------------------
    -- Parser Tests
    ---------------------------------------------------------------------------

    test("Parser builds AST for simple command", function()
        local ast = C3.Parser.ParseString("echo hello")
        return ast and ast.type == "pipeline"
    end)

    test("Parser builds pipeline AST", function()
        local ast = C3.Parser.ParseString("bags | first")
        return ast and ast.type == "pipeline" and #ast.commands == 2
    end)

    test("Parser handles chain (&&)", function()
        local ast = C3.Parser.ParseString("echo a && echo b")
        return ast and ast.type == "chain"
    end)

    ---------------------------------------------------------------------------
    -- Type System Tests
    ---------------------------------------------------------------------------

    test("Create Text type", function()
        local text = C3.Types.Text("hello")
        return text and text._type == "Text" and text.content == "hello"
    end)

    test("Create Error type", function()
        local err = C3.Types.Error("something failed")
        return err and err._type == "Error"
    end)

    test("Create Item type", function()
        local item = C3.Types.Create("Item", {
            id = 19019,
            name = "Thunderfury",
            quality = 5,
        })
        return item and item._type == "Item" and item.name == "Thunderfury"
    end)

    ---------------------------------------------------------------------------
    -- VFS Tests
    ---------------------------------------------------------------------------

    test("VFS exists", function()
        return C3:GetVFS() ~= nil
    end)

    test("VFS has root", function()
        local vfs = C3:GetVFS()
        return vfs:Exists("/")
    end)

    test("VFS has /home", function()
        local vfs = C3:GetVFS()
        return vfs:Exists("/home")
    end)

    test("VFS can write and read file", function()
        local vfs = C3:GetVFS()
        local testPath = "/tmp/test.txt"
        local content = "Hello Commander!"

        local ok = vfs:Write(testPath, content)
        if not ok then return false, "write failed" end

        local read = vfs:Read(testPath)
        if read ~= content then return false, "content mismatch" end

        -- Cleanup
        vfs:Delete(testPath)
        return true
    end)

    test("VFS mkdir and rmdir", function()
        local vfs = C3:GetVFS()
        local testDir = "/tmp/testdir"

        local ok = vfs:MakeDir(testDir)
        if not ok then return false, "mkdir failed" end

        if not vfs:IsDirectory(testDir) then return false, "not a directory" end

        vfs:Delete(testDir)
        return not vfs:Exists(testDir)
    end)

    ---------------------------------------------------------------------------
    -- Path Tests
    ---------------------------------------------------------------------------

    test("Paths.Normalize", function()
        return C3.Paths.Normalize("/home/../tmp") == "/tmp"
    end)

    test("Paths.Join", function()
        return C3.Paths.Join("/home", "scripts", "test.lua") == "/home/scripts/test.lua"
    end)

    test("Paths.Parent", function()
        return C3.Paths.Parent("/home/scripts/test.lua") == "/home/scripts"
    end)

    test("Paths.Filename", function()
        return C3.Paths.Filename("/home/scripts/test.lua") == "test.lua"
    end)

    test("Paths.Extension", function()
        return C3.Paths.Extension("/home/test.lua") == "lua"
    end)

    ---------------------------------------------------------------------------
    -- Command Registry Tests
    ---------------------------------------------------------------------------

    test("Command registry exists", function()
        return C3.Command ~= nil and C3.Command.Define ~= nil
    end)

    test("echo command exists", function()
        return C3.Commands.echo ~= nil
    end)

    test("where command exists", function()
        return C3.Commands.where ~= nil
    end)

    test("bags command exists", function()
        return C3.Commands.bags ~= nil
    end)

    ---------------------------------------------------------------------------
    -- Execution Tests
    ---------------------------------------------------------------------------

    test("Execute echo", function()
        local result = C3:Query("echo hello world")
        return result and result._type == "Text"
    end)

    test("Execute version", function()
        local result = C3:Query("version")
        return result and result._type == "Text" and result.content:find("Commander")
    end)

    test("Execute pwd", function()
        local result = C3:Query("pwd")
        return result and result._type == "Text"
    end)

    ---------------------------------------------------------------------------
    -- Pipeline Tests (bags | where | first)
    ---------------------------------------------------------------------------

    test("Pipeline: bags produces items", function()
        -- This may produce empty results if bags are empty, but shouldn't error
        local result = C3:Query("bags")
        -- Result could be an iterator or array
        return result ~= nil
    end)

    test("Pipeline: bags | first", function()
        local result = C3:Query("bags | first")
        -- May be nil if bags empty, or an Item
        return true -- Just testing it doesn't error
    end)

    test("Pipeline: bags | count", function()
        local result = C3:Query("bags | count")
        return result and (result._type == "Number" or type(result.value) == "number")
    end)

    ---------------------------------------------------------------------------
    -- Session Tests
    ---------------------------------------------------------------------------

    test("Session manager exists", function()
        return C3.SessionManager ~= nil
    end)

    test("Can get active session", function()
        local session = C3:GetSession()
        return session ~= nil and session.id ~= nil
    end)

    test("Session history works", function()
        local session = C3:GetSession()
        session:AddHistory("test command")
        local prev = session:HistoryPrev()
        return prev == "test command"
    end)

    test("Session environment works", function()
        local session = C3:GetSession()
        session:SetEnv("TEST_VAR", 123)
        return session:GetEnv("TEST_VAR") == 123
    end)

    ---------------------------------------------------------------------------
    -- Buffer Tests
    ---------------------------------------------------------------------------

    test("VirtualBuffer exists", function()
        return C3.VirtualBuffer ~= nil
    end)

    test("BufferLine exists", function()
        return C3.BufferLine ~= nil
    end)

    test("Can create buffer and add lines", function()
        local buffer = C3.VirtualBuffer:new()
        buffer:AddLine("Test line 1")
        buffer:AddLine("Test line 2")
        return buffer:GetLineCount() == 2
    end)

    test("Buffer viewport works", function()
        local buffer = C3.VirtualBuffer:new({ viewportSize = 10 })
        for i = 1, 20 do
            buffer:AddLine("Line " .. i)
        end
        local visible = buffer:GetViewport()
        return #visible <= 10
    end)

    ---------------------------------------------------------------------------
    -- Summary
    ---------------------------------------------------------------------------

    print("")
    print("|cFF00FF00[C3 Test]|r ================================")
    print(string.format("|cFF00FF00[C3 Test]|r Passed: %d", passed))
    print(string.format("|cFF%s[C3 Test]|r Failed: %d",
        failed > 0 and "FF0000" or "00FF00", failed))
    print("|cFF00FF00[C3 Test]|r ================================")

    if failed == 0 then
        print("|cFF00FF00[C3 Test]|r All tests passed! System is ready.")
    else
        print("|cFFFF0000[C3 Test]|r Some tests failed. Check output above.")
    end

    -- Store test results
    C3._testResults = {
        passed = passed,
        failed = failed,
        total = passed + failed,
    }
end)

return true
