package exec_test

import (
	"context"
	"os"
	"path/filepath"
	"testing"
	"time"

	iexec "github.com/mathiasbq/supervisor/internal/exec"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

// fakeClaudePath writes a shell script that prints fixed output and returns its path.
func fakeClaudePath(t *testing.T, output string, exitCode int) string {
	t.Helper()
	dir := t.TempDir()
	script := filepath.Join(dir, "claude")
	var content string
	if exitCode != 0 {
		content = "#!/bin/sh\necho 'error' >&2\nexit 1\n"
	} else {
		content = "#!/bin/sh\necho '" + output + "'\n"
	}
	require.NoError(t, os.WriteFile(script, []byte(content), 0755))
	return script
}

func TestExecutorParsesValidResult(t *testing.T) {
	validJSON := `{"status":"pass","phase":"red","skill":"tdd","file_path":"/tmp/x_test.go","runner_output":"FAIL","verified":true,"model_used":"self","message":"ok"}`
	claude := fakeClaudePath(t, validJSON, 0)

	ex := iexec.New(iexec.Config{
		ClaudeBinary: claude,
		SystemPrompt: "you are a supervisor",
		Timeout:      5 * time.Second,
	})

	result, err := ex.Run(context.Background(), iexec.Request{
		SkillPrompt: "tdd rules",
		TaskPrompt:  "run red phase",
	})
	require.NoError(t, err)
	assert.Equal(t, "pass", result.Status)
	assert.True(t, result.Verified)
}

func TestExecutorReturnsErrorOnNonZeroExit(t *testing.T) {
	claude := fakeClaudePath(t, "", 1)

	ex := iexec.New(iexec.Config{
		ClaudeBinary: claude,
		SystemPrompt: "you are a supervisor",
		Timeout:      5 * time.Second,
	})

	_, err := ex.Run(context.Background(), iexec.Request{TaskPrompt: "fail"})
	assert.Error(t, err)
}

func TestExecutorTimesOut(t *testing.T) {
	dir := t.TempDir()
	script := filepath.Join(dir, "claude")
	require.NoError(t, os.WriteFile(script, []byte("#!/bin/sh\nsleep 60\n"), 0755))

	ex := iexec.New(iexec.Config{
		ClaudeBinary: script,
		SystemPrompt: "you are a supervisor",
		Timeout:      100 * time.Millisecond,
	})

	_, err := ex.Run(context.Background(), iexec.Request{TaskPrompt: "slow"})
	assert.ErrorContains(t, err, "timeout")
}
