package handlers_test

import (
	"context"
	"encoding/json"
	"os"
	"path/filepath"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"github.com/yan1h/agent-coding-workflow/internal/acp/handlers"
)

func TestFsList_HappyPath(t *testing.T) {
	t.Parallel()
	tmp := t.TempDir()
	require.NoError(t, os.WriteFile(filepath.Join(tmp, "a.txt"), []byte("hi"), 0o644))
	require.NoError(t, os.MkdirAll(filepath.Join(tmp, "sub"), 0o755))

	h := handlers.NewFsListHandler()
	sess := handlers.SessionContext{CwdPath: tmp}
	res := h.Handle(context.Background(), sess, mustJSON(t, map[string]any{"sessionId": "x", "path": "."}))
	require.Nil(t, res.Err)

	var out struct {
		Entries []struct {
			Name  string `json:"name"`
			IsDir bool   `json:"is_dir"`
			Size  int64  `json:"size"`
		} `json:"entries"`
		Truncated bool `json:"truncated"`
	}
	require.NoError(t, json.Unmarshal(res.OK, &out))
	require.Len(t, out.Entries, 2)
	// Dirs sort first.
	assert.Equal(t, "sub", out.Entries[0].Name)
	assert.True(t, out.Entries[0].IsDir)
	assert.Equal(t, "a.txt", out.Entries[1].Name)
	assert.Equal(t, int64(2), out.Entries[1].Size)
}

func TestFsList_PathOutsideWorktree(t *testing.T) {
	t.Parallel()
	tmp := t.TempDir()
	h := handlers.NewFsListHandler()
	sess := handlers.SessionContext{CwdPath: tmp}
	outside := filepath.Join(filepath.VolumeName(tmp)+string(filepath.Separator), "etc")
	res := h.Handle(context.Background(), sess, mustJSON(t, map[string]any{"sessionId": "x", "path": outside}))
	require.NotNil(t, res.Err)
	assert.Equal(t, -32001, res.Err.Code)
}

func TestFsList_NotFound(t *testing.T) {
	t.Parallel()
	tmp := t.TempDir()
	h := handlers.NewFsListHandler()
	sess := handlers.SessionContext{CwdPath: tmp}
	res := h.Handle(context.Background(), sess, mustJSON(t, map[string]any{"sessionId": "x", "path": "missing"}))
	require.NotNil(t, res.Err)
	assert.Equal(t, -32603, res.Err.Code)
}

func TestFsList_MaxEntriesCap(t *testing.T) {
	t.Parallel()
	tmp := t.TempDir()
	for i := 0; i < 5; i++ {
		require.NoError(t, os.WriteFile(filepath.Join(tmp, string(rune('a'+i))+".txt"), []byte("x"), 0o644))
	}
	h := &handlers.FsListHandler{MaxEntries: 2}
	sess := handlers.SessionContext{CwdPath: tmp}
	res := h.Handle(context.Background(), sess, mustJSON(t, map[string]any{"sessionId": "x", "path": "."}))
	require.Nil(t, res.Err)
	var out struct {
		Entries   []any `json:"entries"`
		Truncated bool  `json:"truncated"`
	}
	require.NoError(t, json.Unmarshal(res.OK, &out))
	require.Len(t, out.Entries, 2)
	require.True(t, out.Truncated)
}
