package codeindex

import (
	"context"
	"encoding/json"
	"testing"
	"time"

	"github.com/google/uuid"
	"github.com/stretchr/testify/require"

	"github.com/yan1h/agent-coding-workflow/internal/infra/git"
	"github.com/yan1h/agent-coding-workflow/internal/infra/llm"
	"github.com/yan1h/agent-coding-workflow/internal/jobs"
)

type fakeEnqueuer struct{ count int }

func (f *fakeEnqueuer) Enqueue(_ context.Context, typ jobs.JobType, _ json.RawMessage, _ time.Time, _ int32) (*jobs.Job, error) {
	f.count++
	return &jobs.Job{ID: uuid.New(), Type: typ}, nil
}

func TestService_EnqueueBuild_DisabledEmbedder(t *testing.T) {
	repo := newFakeRepo()
	enq := &fakeEnqueuer{}
	svc := NewService(repo, fakeLocator{}, nil, fakeEmbedSel{err: ErrEmbeddingDisabled}, enq, 50)
	_, err := svc.EnqueueBuild(context.Background(), uuid.New(), nil, "abc123")
	require.ErrorIs(t, err, ErrEmbeddingDisabled)
	require.Equal(t, 0, enq.count)
}

func TestService_EnqueueBuild_CreatesRunAndEnqueuesOnce(t *testing.T) {
	dir, sha := tempGitRepo(t)
	wsID := uuid.New()
	repo := newFakeRepo()
	enq := &fakeEnqueuer{}
	gitr := git.NewDefaultRunner(git.DefaultConfig())
	svc := NewService(repo, fakeLocator{dir: dir, wsID: wsID}, gitr,
		fakeEmbedSel{emb: llm.NewFakeEmbedder()}, enq, 50)

	run, err := svc.EnqueueBuild(context.Background(), wsID, nil, sha)
	require.NoError(t, err)
	require.Equal(t, sha, run.CommitSHA)
	require.Equal(t, 1, enq.count)
	require.Len(t, repo.runs, 1)

	// Re-enqueue at the same commit while pending → no new job, no new run.
	run2, err := svc.EnqueueBuild(context.Background(), wsID, nil, sha)
	require.NoError(t, err)
	require.Equal(t, run.ID, run2.ID)
	require.Equal(t, 1, enq.count, "idempotent: pending run is reused")
	require.Len(t, repo.runs, 1)
}

func TestService_Search_NoCompletedRun(t *testing.T) {
	repo := newFakeRepo()
	svc := NewService(repo, fakeLocator{}, nil, fakeEmbedSel{emb: llm.NewFakeEmbedder()}, &fakeEnqueuer{}, 50)
	_, err := svc.Search(context.Background(), uuid.New(), SearchQuery{Text: "foo"})
	require.Error(t, err) // no completed index yet
}

func TestService_Search_EmptyQuery(t *testing.T) {
	repo := newFakeRepo()
	svc := NewService(repo, fakeLocator{}, nil, fakeEmbedSel{emb: llm.NewFakeEmbedder()}, &fakeEnqueuer{}, 50)
	_, err := svc.Search(context.Background(), uuid.New(), SearchQuery{Text: ""})
	require.Error(t, err)
}
