package schema

import (
	"context"
	"errors"
	"testing"

	"github.com/stretchr/testify/require"
)

type fakeSchemaQueryer struct {
	schemaName string
	tables     []string
	columns    [][2]string
	queryErr   error
}

func (queryer fakeSchemaQueryer) QueryRow(context.Context, string, ...any) schemaRow {
	return fakeSchemaRow{schemaName: queryer.schemaName}
}

func (queryer fakeSchemaQueryer) Query(_ context.Context, query string, _ ...any) (schemaRows, error) {
	if queryer.queryErr != nil {
		return nil, queryer.queryErr
	}
	if query == "tables" {
		values := make([][]string, 0, len(queryer.tables))
		for _, table := range queryer.tables {
			values = append(values, []string{table})
		}
		return &fakeSchemaRows{values: values}, nil
	}
	values := make([][]string, 0, len(queryer.columns))
	for _, column := range queryer.columns {
		values = append(values, []string{column[0], column[1]})
	}
	return &fakeSchemaRows{values: values}, nil
}

type fakeSchemaRow struct{ schemaName string }

func (row fakeSchemaRow) Scan(dest ...any) error {
	*(dest[0].(*string)) = row.schemaName
	return nil
}

type fakeSchemaRows struct {
	values [][]string
	index  int
}

func (*fakeSchemaRows) Close()          {}
func (*fakeSchemaRows) Err() error      { return nil }
func (rows *fakeSchemaRows) Next() bool { return rows.index < len(rows.values) }
func (rows *fakeSchemaRows) Scan(dest ...any) error {
	current := rows.values[rows.index]
	rows.index++
	for i := range dest {
		*(dest[i].(*string)) = current[i]
	}
	return nil
}

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

	queryer := fakeSchemaQueryer{schemaName: "agentteam", tables: []string{requiredTableNames[0]}}
	err := verify(context.Background(), queryer, "schema", "tables", "columns")
	require.ErrorContains(t, err, "missing org tables")
	require.ErrorContains(t, err, "organization_settings.status")
}

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

	columns := make([][2]string, 0)
	for table, names := range requiredColumnNames {
		for _, name := range names {
			columns = append(columns, [2]string{table, name})
		}
	}
	err := verify(context.Background(), fakeSchemaQueryer{schemaName: "agentteam", tables: requiredTableNames, columns: columns}, "schema", "tables", "columns")
	require.NoError(t, err)
}

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

	err := verify(context.Background(), fakeSchemaQueryer{schemaName: "agentteam", queryErr: errors.New("boom")}, "schema", "tables", "columns")
	require.ErrorContains(t, err, "check org tables")
}
