--[[
    Commander 3.0 - VFS Test Suite

    Tests for Virtual Filesystem:
    - pwd, cd
    - mkdir, rmdir
    - ls, tree
    - write, cat, rm
    - stat
]]

local ADDON_NAME, C3 = ...

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

-- Test paths - use timestamped dir for cleanup
local TEST_DIR = "/tmp/c3_test_" .. time()
local TEST_FILE = TEST_DIR .. "/test.txt"

-------------------------------------------------------------------------------
-- Setup/Teardown
-------------------------------------------------------------------------------

suite.beforeAll = function()
    local vfs = C3:GetVFS()
    if vfs and vfs.MakeDirP then
        vfs:MakeDirP(TEST_DIR)
        -- Ensure home directories exist for cd ~ and cd .. tests
        vfs:MakeDirP("/home/scripts")
    elseif vfs and vfs.MakeDir then
        vfs:MakeDir("/tmp")
        vfs:MakeDir(TEST_DIR)
        -- Ensure home directories exist
        if not vfs:Exists("/home") then
            vfs:MakeDir("/home")
        end
        if not vfs:Exists("/home/scripts") then
            vfs:MakeDir("/home/scripts")
        end
    end
end

suite.afterAll = function()
    local vfs = C3:GetVFS()
    if vfs then
        -- Clean up test directory
        if vfs.DeleteRecursive then
            pcall(function() vfs:DeleteRecursive(TEST_DIR) end)
        elseif vfs.Delete then
            pcall(function() vfs:Delete(TEST_FILE) end)
            pcall(function() vfs:Delete(TEST_DIR) end)
        end
    end
end

-------------------------------------------------------------------------------
-- VFS Module Tests
-------------------------------------------------------------------------------

Framework:Test(suite, "VFS exists and is initialized", function()
    local vfs = C3:GetVFS()
    Assert.notNil(vfs, "VFS should exist")
end)

Framework:Test(suite, "VFS has core methods", function()
    local vfs = C3:GetVFS()
    Assert.notNil(vfs.Read, "VFS should have Read")
    Assert.notNil(vfs.Write, "VFS should have Write")
    Assert.notNil(vfs.Exists, "VFS should have Exists")
    Assert.notNil(vfs.Delete, "VFS should have Delete")
end)

-------------------------------------------------------------------------------
-- pwd Command Tests
-------------------------------------------------------------------------------

Framework:Test(suite, "pwd returns current directory", function()
    local result = C3:Query("pwd")
    Assert.notNil(result)
    Assert.hasType(result, "Text")
    Assert.contains(result.content, "/", "pwd should return a path")
end)

Framework:Test(suite, "pwd default is /home", function()
    local vfs = C3:GetVFS()
    local originalCwd = vfs:GetCwd()

    vfs:SetCwd("/home")
    local result = C3:Query("pwd")
    Assert.equals("/home", result.content)

    -- Restore
    vfs:SetCwd(originalCwd)
end)

-------------------------------------------------------------------------------
-- cd Command Tests
-------------------------------------------------------------------------------

Framework:Test(suite, "cd changes directory", function()
    local vfs = C3:GetVFS()
    local originalCwd = vfs:GetCwd()

    C3:Query("cd /tmp")
    Assert.equals("/tmp", vfs:GetCwd())

    -- Restore
    vfs:SetCwd(originalCwd)
end)

Framework:Test(suite, "cd ~ goes to user home directory", function()
    local vfs = C3:GetVFS()
    local originalCwd = vfs:GetCwd()

    C3:Query("cd ~")
    -- ~ expands to user's home: /home/Realm/Character
    local cwd = vfs:GetCwd()
    Assert.isTrue(cwd:match("^/home"), "cd ~ should go to a /home subdirectory")

    vfs:SetCwd(originalCwd)
end)

Framework:Test(suite, "cd to nonexistent path fails", function()
    local result = C3:Query("cd /nonexistent_path_xyz_123")
    Assert.hasType(result, "Error")
end)

Framework:Test(suite, "cd .. goes to parent", function()
    local vfs = C3:GetVFS()
    local originalCwd = vfs:GetCwd()

    vfs:SetCwd("/home/scripts")
    C3:Query("cd ..")
    Assert.equals("/home", vfs:GetCwd())

    vfs:SetCwd(originalCwd)
end)

-------------------------------------------------------------------------------
-- mkdir Command Tests
-------------------------------------------------------------------------------

Framework:Test(suite, "mkdir creates directory", function()
    local vfs = C3:GetVFS()
    local newDir = TEST_DIR .. "/newdir"

    local result = C3:Query("mkdir " .. newDir)
    Assert.notNil(result)
    Assert.isTrue(vfs:Exists(newDir), "directory should exist after mkdir")
    Assert.isTrue(vfs:IsDirectory(newDir), "should be a directory")

    -- Cleanup
    vfs:Delete(newDir)
end)

Framework:Test(suite, "mkdir on existing dir returns error", function()
    local vfs = C3:GetVFS()
    local existingDir = TEST_DIR .. "/existing"
    vfs:MakeDir(existingDir)

    local result = C3:Query("mkdir " .. existingDir)
    -- Should return error since dir exists
    Assert.hasType(result, "Error")

    vfs:Delete(existingDir)
end)

-------------------------------------------------------------------------------
-- ls Command Tests
-------------------------------------------------------------------------------

Framework:Test(suite, "ls lists directory contents", function()
    local result = C3:Query("ls /")
    Assert.notNil(result)
end)

Framework:Test(suite, "ls current directory works", function()
    local result = C3:Query("ls")
    Assert.notNil(result)
end)

Framework:Test(suite, "ls on empty dir shows appropriate output", function()
    local vfs = C3:GetVFS()
    local emptyDir = TEST_DIR .. "/emptydir"
    vfs:MakeDir(emptyDir)

    local result = C3:Query("ls " .. emptyDir)
    Assert.notNil(result)

    vfs:Delete(emptyDir)
end)

Framework:Test(suite, "ls on nonexistent path returns error", function()
    local result = C3:Query("ls /nonexistent_xyz_123")
    Assert.hasType(result, "Error")
end)

-------------------------------------------------------------------------------
-- File Write/Read Tests
-------------------------------------------------------------------------------

Framework:Test(suite, "write creates file (via VFS directly)", function()
    local vfs = C3:GetVFS()
    local content = "test content " .. time()

    local ok = vfs:Write(TEST_FILE, content)
    Assert.isTrue(ok, "write should succeed")
    Assert.isTrue(vfs:Exists(TEST_FILE), "file should exist")
end)

Framework:Test(suite, "cat reads file content", function()
    local vfs = C3:GetVFS()
    local content = "cat test content"
    vfs:Write(TEST_FILE, content)

    local result = C3:Query("cat " .. TEST_FILE)
    Assert.notNil(result)
    Assert.hasType(result, "Text")
    Assert.equals(content, result.content)
end)

Framework:Test(suite, "cat on nonexistent file returns error", function()
    local result = C3:Query("cat /nonexistent_file_xyz.txt")
    Assert.hasType(result, "Error")
end)

-------------------------------------------------------------------------------
-- rm Command Tests
-------------------------------------------------------------------------------

Framework:Test(suite, "rm deletes file", function()
    local vfs = C3:GetVFS()
    local tempFile = TEST_DIR .. "/todelete.txt"
    vfs:Write(tempFile, "temp")

    Assert.isTrue(vfs:Exists(tempFile), "file should exist before rm")

    local result = C3:Query("rm " .. tempFile)
    Assert.notNil(result)
    Assert.isFalse(vfs:Exists(tempFile), "file should not exist after rm")
end)

Framework:Test(suite, "rm on nonexistent file returns error", function()
    local result = C3:Query("rm /nonexistent_xyz_123.txt")
    Assert.hasType(result, "Error")
end)

-------------------------------------------------------------------------------
-- stat Command Tests
-------------------------------------------------------------------------------

Framework:Test(suite, "stat returns file info", function()
    local vfs = C3:GetVFS()
    vfs:Write(TEST_FILE, "stat test")

    local result = C3:Query("stat " .. TEST_FILE)
    Assert.notNil(result)
end)

Framework:Test(suite, "stat on directory works", function()
    local result = C3:Query("stat /home")
    Assert.notNil(result)
end)

-------------------------------------------------------------------------------
-- tree Command Tests
-------------------------------------------------------------------------------

Framework:Test(suite, "tree shows directory structure", function()
    local result = C3:Query("tree /home")
    Assert.notNil(result)
end)

Framework:Test(suite, "tree with depth limit works", function()
    local result = C3:Query("tree / --depth 1")
    Assert.notNil(result)
end)

-------------------------------------------------------------------------------
-- Path Tests (via C3.Paths module)
-------------------------------------------------------------------------------

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

Framework:Test(suite, "Paths.Normalize handles ..", function()
    local result = C3.Paths.Normalize("/home/../tmp")
    Assert.equals("/tmp", result)
end)

Framework:Test(suite, "Paths.Join concatenates paths", function()
    local result = C3.Paths.Join("/home", "scripts", "test.lua")
    Assert.equals("/home/scripts/test.lua", result)
end)

Framework:Test(suite, "Paths.Parent returns parent directory", function()
    local result = C3.Paths.Parent("/home/scripts/test.lua")
    Assert.equals("/home/scripts", result)
end)

Framework:Test(suite, "Paths.Filename extracts filename", function()
    local result = C3.Paths.Filename("/home/scripts/test.lua")
    Assert.equals("test.lua", result)
end)

Framework:Test(suite, "Paths.Extension extracts extension", function()
    local result = C3.Paths.Extension("/home/test.lua")
    Assert.equals("lua", result)
end)

return suite
