package daemon

import (
	"bytes"
	"encoding/json"
	"os"
	"path/filepath"
	"testing"
	"time"

	"github.com/stretchr/testify/require"

	"github.com/tidbcloud/AgentTeam/desktop/internal/api/mcp"
)

func init() {
	if os.Getenv("AGENTTEAM_TEST_DAEMON_HELPER") == "1" {
		select {}
	}
}

func TestDaemonCreatesOneMessageServiceForAllDynamicHandlers(t *testing.T) {
	service := mcp.NewMessageService()
	d := &Daemon{messageService: service}
	require.Same(t, service, d.messageService)
}

func TestCheckPID_Invalid(t *testing.T) {
	tests := []struct {
		pid int
	}{
		{-1},
		{0},
		{MaxPID + 1},
	}

	for _, tt := range tests {
		if checkPID(tt.pid) {
			t.Errorf("checkPID(%d) should return false", tt.pid)
		}
	}
}

func TestCheckPID_CurrentProcess(t *testing.T) {
	if !checkPID(os.Getpid()) {
		t.Error("checkPID(current pid) should return true")
	}
}

func TestDaemonStatus_JSON(t *testing.T) {
	tests := []struct {
		name string
		s    Status
	}{
		{"not running", Status{Running: false}},
		{"running", Status{Running: true, Healthy: true, PID: 12345}},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			data, err := json.Marshal(tt.s)
			if err != nil {
				t.Fatalf("Marshal error = %v", err)
			}

			var decoded Status
			if err := json.Unmarshal(data, &decoded); err != nil {
				t.Fatalf("Unmarshal error = %v", err)
			}
			if decoded.Running != tt.s.Running {
				t.Errorf("Running = %v, want %v", decoded.Running, tt.s.Running)
			}
			if decoded.PID != tt.s.PID {
				t.Errorf("PID = %d, want %d", decoded.PID, tt.s.PID)
			}
			if decoded.Healthy != tt.s.Healthy {
				t.Errorf("Healthy = %v, want %v", decoded.Healthy, tt.s.Healthy)
			}
		})
	}
}

func TestDaemonLogOutputAvoidsDuplicatingLaunchdLogFile(t *testing.T) {
	dir := t.TempDir()
	logPath := filepath.Join(dir, "agentteam.log")
	stderrFile, err := os.OpenFile(logPath, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0644)
	require.NoError(t, err)
	defer stderrFile.Close()

	var rotated bytes.Buffer
	writer := logOutput(stderrFile, logPath, &rotated)
	_, err = writer.Write([]byte("log line\n"))
	require.NoError(t, err)

	require.Equal(t, "log line\n", rotated.String())
	data, err := os.ReadFile(logPath)
	require.NoError(t, err)
	require.Empty(t, string(data), "stderr should be skipped when launchd already redirects it to the daemon log file")
}

func TestDaemonLogOutputKeepsStderrWhenItIsDifferentFromLogFile(t *testing.T) {
	dir := t.TempDir()
	logPath := filepath.Join(dir, "agentteam.log")
	stderrPath := filepath.Join(dir, "stderr.log")
	require.NoError(t, os.WriteFile(logPath, nil, 0644))
	stderrFile, err := os.OpenFile(stderrPath, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0644)
	require.NoError(t, err)
	defer stderrFile.Close()

	var rotated bytes.Buffer
	writer := logOutput(stderrFile, logPath, &rotated)
	_, err = writer.Write([]byte("log line\n"))
	require.NoError(t, err)

	require.Equal(t, "log line\n", rotated.String())
	data, err := os.ReadFile(stderrPath)
	require.NoError(t, err)
	require.Equal(t, "log line\n", string(data))
}

func TestStopUnhealthyProcessInvalidPID(t *testing.T) {
	err := StopUnhealthyProcess(0, time.Second)
	if err == nil {
		t.Fatal("expected error for invalid pid")
	}
}
