package mcp

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

	"github.com/mark3labs/mcp-go/mcp"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	worktree "github.com/aki/amux/internal/worktree"
)

func TestParseWorkspaceURI(t *testing.T) {
	tests := []struct {
		name     string
		uri      string
		wantID   string
		wantPath string
		wantErr  bool
	}{
		{
			name:     "workspace detail URI",
			uri:      "amux://worktree/ws-123",
			wantID:   "ws-123",
			wantPath: "",
		},
		{
			name:     "workspace files root URI",
			uri:      "amux://worktree/ws-123/files",
			wantID:   "ws-123",
			wantPath: "files",
		},
		{
			name:     "workspace files with path",
			uri:      "amux://worktree/ws-123/files/src/main.go",
			wantID:   "ws-123",
			wantPath: "files/src/main.go",
		},
		{
			name:    "invalid URI - no workspace prefix",
			uri:     "amux://invalid/path",
			wantErr: true,
		},
		{
			name:    "invalid URI - missing workspace ID",
			uri:     "amux://worktree/",
			wantErr: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			id, path, err := parseWorktreeURI(tt.uri)
			if tt.wantErr {
				assert.Error(t, err)
			} else {
				require.NoError(t, err)
				assert.Equal(t, tt.wantID, id)
				assert.Equal(t, tt.wantPath, path)
			}
		})
	}
}

func TestHandleWorkspaceDetailResource(t *testing.T) {
	s := setupTestServer(t)

	// Create a test workspace
	ws, err := s.worktreeManager.Create(context.Background(), worktree.CreateOptions{
		Name:        "test-detail",
		Description: "Test workspace for detail resource",
		BaseBranch:  "main",
	})
	require.NoError(t, err)

	ctx := context.Background()
	request := mcp.ReadResourceRequest{
		Params: mcp.ReadResourceParams{
			URI: fmt.Sprintf("amux://worktree/%s", ws.Branch),
		},
	}

	contents, err := s.handleWorktreeDetailResource(ctx, request)
	require.NoError(t, err)
	require.Len(t, contents, 1)

	textContent, ok := contents[0].(*mcp.TextResourceContents)
	require.True(t, ok)
	assert.Equal(t, request.Params.URI, textContent.URI)
	assert.Equal(t, "application/json", textContent.MIMEType)

	// Parse the JSON to verify structure
	var detail map[string]interface{}
	err = json.Unmarshal([]byte(textContent.Text), &detail)
	require.NoError(t, err)

	assert.Equal(t, ws.Branch, detail["id"])
	assert.Equal(t, ws.Branch, detail["name"]) // Name is now same as Branch
	assert.Equal(t, "Test workspace for detail resource", detail["description"])
	assert.Equal(t, "main", detail["baseBranch"])

	// Check paths are included
	paths, ok := detail["paths"].(map[string]interface{})
	require.True(t, ok, "paths field should be present")
	assert.NotEmpty(t, paths["worktree"])

	// Check resources are included
	resources, ok := detail["resources"].(map[string]interface{})
	require.True(t, ok, "resources field should be present")
	assert.Equal(t, fmt.Sprintf("amux://worktree/%s/files", ws.Branch), resources["files"])
}

func TestHandleWorkspaceFilesResource(t *testing.T) {
	s := setupTestServer(t)

	// Create a test workspace
	ws, err := s.worktreeManager.Create(context.Background(), worktree.CreateOptions{
		Name: "test-files",
	})
	require.NoError(t, err)

	// Create test files
	testFile := filepath.Join(ws.Path, "test.txt")
	err = os.WriteFile(testFile, []byte("test content"), 0o644)
	require.NoError(t, err)

	testDir := filepath.Join(ws.Path, "src")
	err = os.MkdirAll(testDir, 0o755)
	require.NoError(t, err)

	t.Run("list directory", func(t *testing.T) {
		ctx := context.Background()
		request := mcp.ReadResourceRequest{
			Params: mcp.ReadResourceParams{
				URI: fmt.Sprintf("amux://worktree/%s/files", ws.Branch),
			},
		}

		contents, err := s.handleWorktreeFilesResource(ctx, request)
		require.NoError(t, err)
		require.Len(t, contents, 1)

		textContent, ok := contents[0].(*mcp.TextResourceContents)
		require.True(t, ok)
		assert.Equal(t, "application/json", textContent.MIMEType)

		// Parse the JSON to verify structure
		var files []map[string]interface{}
		err = json.Unmarshal([]byte(textContent.Text), &files)
		require.NoError(t, err)

		// Should have at least test.txt and src directory
		assert.GreaterOrEqual(t, len(files), 2)

		// Find test.txt and src
		foundFile := false
		foundDir := false
		for _, f := range files {
			if f["name"] == "test.txt" {
				foundFile = true
				assert.Equal(t, "file", f["type"])
				assert.EqualValues(t, 12, f["size"]) // "test content"
			}
			if f["name"] == "src" {
				foundDir = true
				assert.Equal(t, "directory", f["type"])
			}
		}
		assert.True(t, foundFile, "test.txt not found")
		assert.True(t, foundDir, "src directory not found")
	})

	t.Run("read file", func(t *testing.T) {
		ctx := context.Background()
		request := mcp.ReadResourceRequest{
			Params: mcp.ReadResourceParams{
				URI: fmt.Sprintf("amux://worktree/%s/files/test.txt", ws.Branch),
			},
		}

		contents, err := s.handleWorktreeFilesResource(ctx, request)
		require.NoError(t, err)
		require.Len(t, contents, 1)

		textContent, ok := contents[0].(*mcp.TextResourceContents)
		require.True(t, ok)
		assert.Equal(t, "text/plain", textContent.MIMEType)
		assert.Equal(t, "test content", textContent.Text)
	})
}

func TestRegisterResourceTemplates(t *testing.T) {
	s := setupTestServer(t)

	// Test that registerResourceTemplates completes without error
	// Since MCPServer doesn't expose ListResourceTemplates method,
	// we'll test by attempting to use the handlers

	// Create a test workspace
	ws, err := s.worktreeManager.Create(context.Background(), worktree.CreateOptions{
		Name: "test-templates",
	})
	require.NoError(t, err)

	ctx := context.Background()

	// Test workspace detail handler
	detailReq := mcp.ReadResourceRequest{
		Params: mcp.ReadResourceParams{
			URI: fmt.Sprintf("amux://worktree/%s", ws.Branch),
		},
	}
	contents, err := s.handleWorktreeDetailResource(ctx, detailReq)
	require.NoError(t, err)
	assert.NotEmpty(t, contents)

	// Test workspace files handler
	filesReq := mcp.ReadResourceRequest{
		Params: mcp.ReadResourceParams{
			URI: fmt.Sprintf("amux://worktree/%s/files", ws.Branch),
		},
	}
	contents, err = s.handleWorktreeFilesResource(ctx, filesReq)
	require.NoError(t, err)
	assert.NotEmpty(t, contents)
}
