package runtime

import (
	"context"
	"reflect"
	"strings"
	"testing"

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

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

	queryer := &scriptedRuntimeQueryer{
		capabilityRows: []scriptedRuntimeCapabilityRow{
			{machineID: "mac-a", runtime: strPtr("codex"), model: " gpt-5.4 ", effort: " high "},
			{machineID: "mac-a", runtime: strPtr(""), model: "ignored", effort: "ignored"},
			{machineID: "mac-b", runtime: nil},
		},
	}
	capabilities, defaults, err := LoadMachineRuntimeCapabilities(context.Background(), queryer, []string{" mac-a ", "mac-b", "mac-a", ""})
	if err != nil {
		t.Fatalf("LoadMachineRuntimeCapabilities returned error: %v", err)
	}
	if got, want := queryer.args, []any{"mac-a", "mac-b"}; !reflect.DeepEqual(got, want) {
		t.Fatalf("query args = %#v, want %#v", got, want)
	}
	if !strings.Contains(queryer.query, "WITH requested_machine_ids AS") {
		t.Fatalf("query missing requested_machine_ids CTE:\n%s", queryer.query)
	}
	if got, want := capabilities["mac-a"], []string{"codex"}; !reflect.DeepEqual(got, want) {
		t.Fatalf("mac-a capabilities = %#v, want %#v", got, want)
	}
	if got, want := capabilities["mac-b"], []string{}; !reflect.DeepEqual(got, want) {
		t.Fatalf("mac-b capabilities = %#v, want %#v", got, want)
	}
	if got, want := defaults["mac-a"]["codex"], (RuntimeDefaults{Model: "gpt-5.4", ReasoningEffort: "high"}); got != want {
		t.Fatalf("codex defaults = %#v, want %#v", got, want)
	}
}

type scriptedRuntimeQueryer struct {
	query          string
	args           []any
	capabilityRows []scriptedRuntimeCapabilityRow
}

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

func (queryer *scriptedRuntimeQueryer) Query(_ context.Context, query string, args ...any) (coredb.Rows, error) {
	queryer.query = query
	queryer.args = append([]any(nil), args...)
	return &scriptedRuntimeCapabilityRows{rows: queryer.capabilityRows}, nil
}

type unusedRuntimeRow struct{}

func (unusedRuntimeRow) Scan(...any) error { return nil }

type scriptedRuntimeCapabilityRow struct {
	machineID string
	runtime   *string
	model     string
	effort    string
}

type scriptedRuntimeCapabilityRows struct {
	rows []scriptedRuntimeCapabilityRow
	idx  int
}

func (rows *scriptedRuntimeCapabilityRows) Close()     {}
func (rows *scriptedRuntimeCapabilityRows) Err() error { return nil }
func (rows *scriptedRuntimeCapabilityRows) Next() bool { return rows.idx < len(rows.rows) }
func (rows *scriptedRuntimeCapabilityRows) Scan(dest ...any) error {
	row := rows.rows[rows.idx]
	rows.idx++
	*(dest[0].(*string)) = row.machineID
	*(dest[1].(**string)) = row.runtime
	*(dest[2].(*string)) = row.model
	*(dest[3].(*string)) = row.effort
	return nil
}

func strPtr(value string) *string { return &value }
