package server

import (
	"bytes"
	"context"
	"encoding/json"
	"errors"
	"log/slog"
	"testing"
	"time"

	"github.com/stretchr/testify/require"

	"github.com/tidbcloud/AgentTeam/internal/observability/logging"
)

func TestKBPeriodicWorkerRunsImmediatelyAndStopsWithContext(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())
	runs := make(chan struct{}, 1)
	done := startKBPeriodicWorkers(ctx, nil, kbPeriodicWorker{
		interval:       time.Hour,
		runImmediately: true,
		run: func(context.Context) error {
			runs <- struct{}{}
			return nil
		},
	})

	select {
	case <-runs:
	case <-time.After(time.Second):
		require.Fail(t, "immediate KB worker did not run")
	}
	cancel()
	select {
	case <-done:
	case <-time.After(time.Second):
		require.Fail(t, "KB worker did not stop after cancellation")
	}
}

func TestKBPeriodicWorkerUsesOwnerLoggerAndClassifiesFailure(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())
	var output bytes.Buffer
	logger := slog.New(logging.WrapHandler(slog.NewJSONHandler(&output, nil))).With(slog.String("domain", "kb"))
	done := startKBPeriodicWorkers(ctx, logger, kbPeriodicWorker{
		interval:       time.Hour,
		runImmediately: true,
		component:      "source_mirror_worker",
		errMsg:         "kb source mirror worker tick failed",
		run: func(context.Context) error {
			return errors.New("secret upstream body /private/worktree")
		},
	})
	cancel()
	select {
	case <-done:
	case <-time.After(time.Second):
		require.Fail(t, "KB worker did not stop after cancellation")
	}

	var entry map[string]any
	require.NoError(t, json.Unmarshal(bytes.TrimSpace(output.Bytes()), &entry))
	require.Equal(t, "kb", entry["domain"])
	require.Equal(t, "source_mirror_worker", entry["component"])
	require.Equal(t, "worker_failed", entry["error_class"])
	require.NotContains(t, output.String(), "secret upstream body")
	require.NotContains(t, output.String(), "/private/worktree")
	require.NotContains(t, entry, "error")
}
