package schema

import (
	"testing"

	"github.com/nexuscrm/shared/pkg/constants"
)

func TestExpandPolymorphicDiscriminatorColumns(t *testing.T) {
	def := TableDefinition{
		TableName: "Workitem",
		Columns: []ColumnDefinition{
			{Name: "Id", Type: "VARCHAR(255)"},
			{
				Name:          "ActorId",
				Label:         "Actor",
				Type:          "VARCHAR(255)",
				LogicalType:   string(constants.FieldTypeReference),
				ReferenceTo:   []string{"User"},
				IsPolymorphic: true,
			},
			{
				Name:        "WhatId",
				Type:        "VARCHAR(255)",
				LogicalType: string(constants.FieldTypeReference),
				ReferenceTo: []string{"Account", "Opportunity"},
			},
		},
	}

	got := ExpandPolymorphicDiscriminatorColumns(def)

	assertColumnOrder(t, got.Columns, []string{"Id", "ActorId", "ActorId_type", "WhatId", "WhatId_type"})
	actorType := findTestColumn(t, got.Columns, "ActorId_type")
	if actorType.Type != "VARCHAR(255)" || actorType.LogicalType != string(constants.FieldTypeString) || !actorType.Nullable {
		t.Fatalf("ActorId_type shape = %#v, want nullable VARCHAR string discriminator", actorType)
	}
	if actorType.GeneratedForPolymorphicReference != "ActorId" {
		t.Fatalf("ActorId_type GeneratedForPolymorphicReference = %q, want ActorId", actorType.GeneratedForPolymorphicReference)
	}
}

func TestExpandPolymorphicDiscriminatorColumnsIsIdempotent(t *testing.T) {
	def := TableDefinition{
		TableName: "Workitem",
		Columns: []ColumnDefinition{
			{
				Name:          "ActorId",
				Type:          "VARCHAR(255)",
				LogicalType:   string(constants.FieldTypeReference),
				ReferenceTo:   []string{"User"},
				IsPolymorphic: true,
			},
			{Name: "ActorId_type", Type: "VARCHAR(255)", LogicalType: string(constants.FieldTypeString), Nullable: true},
		},
	}

	got := ExpandPolymorphicDiscriminatorColumns(def)

	assertColumnOrder(t, got.Columns, []string{"ActorId", "ActorId_type"})
	actorType := findTestColumn(t, got.Columns, "ActorId_type")
	if actorType.GeneratedForPolymorphicReference != "ActorId" {
		t.Fatalf("existing ActorId_type GeneratedForPolymorphicReference = %q, want ActorId", actorType.GeneratedForPolymorphicReference)
	}
}

func assertColumnOrder(t *testing.T, got []ColumnDefinition, want []string) {
	t.Helper()
	if len(got) != len(want) {
		t.Fatalf("column count = %d, want %d (%v)", len(got), len(want), want)
	}
	for i, wantName := range want {
		if got[i].Name != wantName {
			t.Fatalf("column[%d] = %q, want %q (all=%v)", i, got[i].Name, wantName, got)
		}
	}
}

func findTestColumn(t *testing.T, columns []ColumnDefinition, name string) ColumnDefinition {
	t.Helper()
	for _, col := range columns {
		if col.Name == name {
			return col
		}
	}
	t.Fatalf("column %s not found", name)
	return ColumnDefinition{}
}
