--[[
    Commander 3.0 - System Test Suite

    Tests for System & Basic IO:
    - version command
    - echo command
    - Variable expansion ($player, $health, etc.)
    - help command
    - Error handling
]]

local ADDON_NAME, C3 = ...

local Framework = C3.TestFramework
local Assert = Framework.Assert
local suite = Framework:Suite("system")

-------------------------------------------------------------------------------
-- Version Tests
-------------------------------------------------------------------------------

Framework:Test(suite, "version returns expected format", function()
    local result = C3:Query("version")
    Assert.notNil(result, "version should return a result")
    Assert.hasType(result, "Text", "version should return Text type")
    Assert.contains(result.content, "Commander", "version should contain 'Commander'")
    Assert.matches(result.content, "v%d+%.%d+", "version should match version pattern")
end)

Framework:Test(suite, "version shows flavor", function()
    local result = C3:Query("version")
    -- Should contain retail/classic/etc
    Assert.notNil(result.content)
end)

-------------------------------------------------------------------------------
-- Echo Tests
-------------------------------------------------------------------------------

Framework:Test(suite, "echo returns text", function()
    local result = C3:Query("echo Hello World")
    Assert.notNil(result, "echo should return a result")
    Assert.hasType(result, "Text", "echo should return Text type")
    Assert.equals("Hello World", result.content, "echo content mismatch")
end)

Framework:Test(suite, "echo handles quoted strings", function()
    local result = C3:Query('echo "Hello World"')
    Assert.notNil(result)
    Assert.hasType(result, "Text")
    -- May or may not strip quotes depending on implementation
end)

Framework:Test(suite, "echo with no args returns empty or error", function()
    local result = C3:Query("echo")
    -- Should either return empty text or error gracefully
    Assert.notNil(result)
end)

-------------------------------------------------------------------------------
-- Variable Expansion Tests
-------------------------------------------------------------------------------

Framework:Test(suite, "echo $player returns character name", function()
    local result = C3:Query("echo $player")
    Assert.notNil(result, "echo $player should return a result")

    -- Result may be Text type or string depending on implementation
    local content = type(result) == "table" and result.content or tostring(result)
    local playerName = UnitName("player")

    -- Check that result contains the player name (handles realm suffixes)
    Assert.greaterThan(#content, 0, "$player should not be empty")
    Assert.contains(content, playerName, "echo $player should contain character name")
end)

Framework:Test(suite, "echo $health returns number in range", function()
    local result = C3:Query("echo $health")
    Assert.notNil(result, "echo $health should return a result")

    -- $health may return nil/empty on WoW 12.0+ due to secret values when data is restricted
    local healthVal = tonumber(result.content)
    if healthVal then
        Assert.inRange(healthVal, 0, 100, "$health should be 0-100")
    end
    -- Test passes if health is nil (restricted) or valid number
end)

Framework:Test(suite, "echo $class returns valid class", function()
    local result = C3:Query("echo $class")
    Assert.notNil(result)

    -- Result may be Text type or string depending on implementation
    local content = type(result) == "table" and result.content or tostring(result)
    Assert.greaterThan(#content, 0, "$class should not be empty")
end)

Framework:Test(suite, "echo $level returns valid level", function()
    local result = C3:Query("echo $level")
    Assert.notNil(result)

    local level = tonumber(result.content)
    Assert.notNil(level, "$level should be a number")
    -- Level cap varies by expansion (80 in TWW, higher in future)
    Assert.inRange(level, 1, 100, "$level should be 1-100")
end)

Framework:Test(suite, "echo $zone returns zone name", function()
    local result = C3:Query("echo $zone")
    Assert.notNil(result)
    Assert.hasType(result, "Text")
    Assert.greaterThan(#result.content, 0, "$zone should not be empty")
end)

Framework:Test(suite, "echo $gold returns money value", function()
    local result = C3:Query("echo $gold")
    Assert.notNil(result)
    -- Should be a number (copper value)
    local gold = tonumber(result.content)
    Assert.notNil(gold, "$gold should be a number")
    Assert.greaterOrEqual(gold, 0, "$gold should be non-negative")
end)

-------------------------------------------------------------------------------
-- Help Command Tests
-------------------------------------------------------------------------------

Framework:Test(suite, "help command exists", function()
    local result = C3:Query("help")
    Assert.notNil(result, "help should return a result")
end)

Framework:Test(suite, "help for specific command works", function()
    local result = C3:Query("help echo")
    Assert.notNil(result)
    -- Should contain info about echo command
end)

Framework:Test(suite, "help for unknown command shows error", function()
    local result = C3:Query("help nonexistent_xyz")
    -- Should return error or "command not found" message
    Assert.notNil(result)
end)

-------------------------------------------------------------------------------
-- Error Handling Tests
-------------------------------------------------------------------------------

Framework:Test(suite, "unknown command returns error", function()
    local result = C3:Query("nonexistent_command_xyz")
    Assert.hasType(result, "Error", "Unknown command should return Error")
end)

Framework:Test(suite, "syntax error returns error gracefully", function()
    local result = C3:Query("bags | where")
    -- Missing expression should return error, not crash
    Assert.notNil(result)
    if result._type then
        Assert.equals("Error", result._type, "Syntax error should return Error type")
    end
end)

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

Framework:Test(suite, "echo command is registered", function()
    Assert.notNil(C3.Commands.echo, "echo command should be registered")
end)

Framework:Test(suite, "version command is registered", function()
    Assert.notNil(C3.Commands.version, "version command should be registered")
end)

Framework:Test(suite, "clear command is registered", function()
    local hasCommand = C3.Commands.clear or C3.Commands.cls
    Assert.isTrue(hasCommand, "clear/cls command should be registered")
end)

-------------------------------------------------------------------------------
-- Options Command Tests
-------------------------------------------------------------------------------

Framework:Test(suite, "options command is registered", function()
    -- Check command is registered (options opens UI, returns nil with no args)
    Assert.notNil(C3.Commands.options, "options command should be registered")
end)

-------------------------------------------------------------------------------
-- Keybind Command Tests
-------------------------------------------------------------------------------

Framework:Test(suite, "cbind command executes without error", function()
    local result = C3:Query("cbind")
    Assert.notNil(result)
end)

Framework:Test(suite, "kb command executes without error", function()
    local result = C3:Query("kb")
    Assert.notNil(result)
end)

-------------------------------------------------------------------------------
-- Talent Build Command Tests
-------------------------------------------------------------------------------

Framework:Test(suite, "builds command executes without error", function()
    local result = C3:Query("builds")
    Assert.notNil(result)
end)

-------------------------------------------------------------------------------
-- Secrets Module Tests (WoW 12.0+)
-------------------------------------------------------------------------------

Framework:Test(suite, "Secrets module exists", function()
    Assert.notNil(C3.Secrets, "C3.Secrets module should exist")
end)

Framework:Test(suite, "Secrets.IsSecret function exists", function()
    Assert.notNil(C3.Secrets.IsSecret, "IsSecret function should exist")
end)

Framework:Test(suite, "Secrets.SafeValue function exists", function()
    Assert.notNil(C3.Secrets.SafeValue, "SafeValue function should exist")
end)

Framework:Test(suite, "Secrets.UnitHealth wrapper exists", function()
    Assert.notNil(C3.Secrets.UnitHealth, "UnitHealth wrapper should exist")
end)

Framework:Test(suite, "Secrets.GetHealthPercent returns number or nil", function()
    local health = C3.Secrets.GetHealthPercent("player")
    -- Should return number (0-100) or nil if restricted
    if health ~= nil then
        Assert.isType(health, "number", "health should be a number")
        Assert.inRange(health, 0, 100, "health percent should be 0-100")
    end
end)

return suite
