package rewind

import (
	"context"
	"testing"
	"time"

	"github.com/go-sql-driver/mysql"
	"github.com/stretchr/testify/require"

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

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

	query, args, err := BuildDeleteRecoveryPointsByMessageIDsQuery("wsp-1", "agt-1", []string{"msg-1", "msg-2"})
	require.NoError(t, err)
	require.Equal(t, []any{"wsp-1", "agt-1", "msg-1", "msg-2"}, args)
	require.Contains(t, query, "WITH message_ids AS (")
	require.Contains(t, query, "DELETE FROM message_recovery_points AS mrp")
	require.Contains(t, query, "SELECT $3 AS message_id")
	require.Contains(t, query, "SELECT $4 AS message_id")
	require.NotContains(t, query, "RETURNING")
}

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

	preparedAt := time.Date(2026, 4, 4, 17, 30, 0, 0, time.UTC)
	execer := &scriptedExecOnly{results: []scriptedExecResult{
		{tag: testExecResult{}},
		{err: &mysql.MySQLError{Number: 1062, Message: "Duplicate entry 'wsp-1-msg-1-agt-1' for key 'PRIMARY'"}},
		{tag: testExecResult{rowsAffected: 1}},
	}}

	err := WriteMessageRecoveryPointWithExecer(context.Background(), execer, "wsp-1", "msg-1", "agt-1", "thr-1", "snapshot", "ref-1", preparedAt)
	require.NoError(t, err)
	require.Len(t, execer.queries, 3)
	for _, query := range execer.queries {
		require.NotContains(t, query, "ON CONFLICT")
	}
}

// --- Minimal test doubles for portable mutation tests ---

type scriptedExecResult struct {
	tag          testExecResult
	err          error
	rowsAffected int64
}

type testExecResult struct {
	rowsAffected int64
}

func (r testExecResult) RowsAffected() int64 { return r.rowsAffected }

type scriptedExecOnly struct {
	results []scriptedExecResult
	queries []string
	args    [][]any
	idx     int
}

func (s *scriptedExecOnly) Exec(ctx context.Context, query string, args ...any) (coredb.Result, error) {
	s.queries = append(s.queries, query)
	s.args = append(s.args, args)
	if s.idx >= len(s.results) {
		return nil, nil
	}
	r := s.results[s.idx]
	s.idx++
	if r.err != nil {
		return nil, r.err
	}
	return r.tag, nil
}
