package message

import (
	"context"
	"database/sql"
	"testing"

	"github.com/stretchr/testify/require"

	"github.com/tidbcloud/AgentTeam/internal/coredb"
)

type missingScopeSearchReadinessRow struct{}

func (missingScopeSearchReadinessRow) Scan(...any) error {
	return sql.ErrNoRows
}

type scopeSearchReadinessDBStub struct {
	query string
	args  []any
}

func (stub *scopeSearchReadinessDBStub) Database() string { return "tidb" }

func (stub *scopeSearchReadinessDBStub) QueryRow(_ context.Context, query string, args ...any) coredb.Row {
	stub.query = query
	stub.args = append([]any(nil), args...)
	return missingScopeSearchReadinessRow{}
}

func (*scopeSearchReadinessDBStub) Query(context.Context, string, ...any) (coredb.Rows, error) {
	panic("unexpected Query")
}

func (*scopeSearchReadinessDBStub) Exec(context.Context, string, ...any) (coredb.Result, error) {
	panic("unexpected Exec")
}

func (*scopeSearchReadinessDBStub) BeginTx(context.Context, coredb.TxOptions) (coredb.Tx, error) {
	panic("unexpected BeginTx")
}

type scopeSearchReadinessQueryerStub struct {
	query string
	args  []any
}

func (stub *scopeSearchReadinessQueryerStub) Database() string { return "tidb" }

func (stub *scopeSearchReadinessQueryerStub) QueryRow(_ context.Context, query string, args ...any) coredb.Row {
	stub.query = query
	stub.args = append([]any(nil), args...)
	return missingScopeSearchReadinessRow{}
}

func (*scopeSearchReadinessQueryerStub) Query(context.Context, string, ...any) (coredb.Rows, error) {
	panic("unexpected Query")
}

func TestNewScopeAPIServiceSearchMessagesPreservesStoreDBCapabilities(t *testing.T) {
	t.Parallel()

	db := &scopeSearchReadinessDBStub{}
	api := NewScopeAPIService(New(db, nil, 0, Options{}))

	_, err := api.SearchMessages(context.Background(), ScopeAPISearchRequest{
		WorkspaceID:    "wsp_store",
		ScopeID:        "scp_store",
		ViewerMemberID: "mem_store",
		ViewerType:     ScopeActorAgent,
		Query:          "needle",
	})
	require.EqualError(t, err, "scope message search is unavailable because the scope projection state is missing")
	require.Equal(t, []any{"wsp_store", "scp_store", TiDBMessageSearchProjectionName}, db.args)
	require.Contains(t, db.query, "FROM scope_message_search_state")
}

func TestNewScopeAPIServiceForQueryerSearchMessagesPreservesBackendMetadata(t *testing.T) {
	t.Parallel()

	queryer := &scopeSearchReadinessQueryerStub{}
	api := NewScopeAPIServiceForQueryer(queryer)

	_, err := api.SearchMessages(context.Background(), ScopeAPISearchRequest{
		WorkspaceID:    "wsp_queryer",
		ScopeID:        "scp_queryer",
		ViewerMemberID: "mem_queryer",
		ViewerType:     ScopeActorAgent,
		Query:          "needle",
	})
	require.EqualError(t, err, "scope message search is unavailable because the scope projection state is missing")
	require.Equal(t, []any{"wsp_queryer", "scp_queryer", TiDBMessageSearchProjectionName}, queryer.args)
	require.Contains(t, queryer.query, "FROM scope_message_search_state")
}
