package persistence

import (
	"testing"

	"github.com/nexuscrm/backend/internal/domain/schema"
	"github.com/nexuscrm/shared/pkg/constants"
	"github.com/nexuscrm/shared/pkg/models"
)

func TestValidateFieldDefinition(t *testing.T) {
	r := &SchemaRepository{db: nil}

	tests := []struct {
		name    string
		field   schema.ColumnDefinition
		wantErr bool
		errMsg  string
	}{
		{
			name: "valid simple string field",
			field: schema.ColumnDefinition{
				Name: "Name",
				Type: "VARCHAR(255)",
			},
			wantErr: false,
		},
		{
			name: "valid boolean field",
			field: schema.ColumnDefinition{
				Name: "IsActive",
				Type: "BOOLEAN",
			},
			wantErr: false,
		},
		{
			name: "valid INT field",
			field: schema.ColumnDefinition{
				Name: "count",
				Type: "INT",
			},
			wantErr: false,
		},
		{
			name: "valid field with underscore prefix",
			field: schema.ColumnDefinition{
				Name: "_system_field",
				Type: "VARCHAR(255)",
			},
			wantErr: false,
		},
		{
			name: "invalid field name with space",
			field: schema.ColumnDefinition{
				Name: "first name",
				Type: "VARCHAR(255)",
			},
			wantErr: true,
			errMsg:  "must be alphanumeric",
		},
		{
			name: "invalid field name with hyphen",
			field: schema.ColumnDefinition{
				Name: "first-name",
				Type: "VARCHAR(255)",
			},
			wantErr: true,
			errMsg:  "must be alphanumeric",
		},
		{
			name: "invalid field name starting with number",
			field: schema.ColumnDefinition{
				Name: "1field",
				Type: "VARCHAR(255)",
			},
			wantErr: true,
			errMsg:  "must be alphanumeric",
		},
		{
			name: "invalid field type",
			field: schema.ColumnDefinition{
				Name: "test_field",
				Type: "COMPLETELY_INVALID_TYPE",
			},
			wantErr: true,
			errMsg:  "invalid field type",
		},
		{
			name: "reference field without referenceTo",
			field: schema.ColumnDefinition{
				Name:        "AccountId",
				Type:        string(constants.FieldTypeReference),
				LogicalType: string(constants.FieldTypeReference),
			},
			wantErr: true,
			errMsg:  "reference_to",
		},
		{
			name: "valid reference field with referenceTo",
			field: schema.ColumnDefinition{
				Name:        "AccountId",
				Type:        string(constants.FieldTypeReference),
				LogicalType: string(constants.FieldTypeReference),
				ReferenceTo: []string{"Account"},
			},
			wantErr: false,
		},
		{
			name: "picklist field without options",
			field: schema.ColumnDefinition{
				Name:        "Status",
				Type:        string(constants.FieldTypePicklist),
				LogicalType: string(constants.FieldTypePicklist),
			},
			wantErr: true,
			errMsg:  "at least one option",
		},
		{
			name: "valid picklist field with options",
			field: schema.ColumnDefinition{
				Name:        "Status",
				Type:        string(constants.FieldTypePicklist),
				LogicalType: string(constants.FieldTypePicklist),
				Options: models.PicklistOptionsFromStrings([]string{"Open", "Closed"}),
			},
			wantErr: false,
		},
		{
			name: "formula field without formula expression",
			field: schema.ColumnDefinition{
				Name:        "Total",
				Type:        string(constants.FieldTypeFormula),
				LogicalType: string(constants.FieldTypeFormula),
				ReturnType:  "double",
			},
			wantErr: true,
			errMsg:  "formula expression",
		},
		{
			name: "formula field without return type",
			field: schema.ColumnDefinition{
				Name:        "Total",
				Type:        string(constants.FieldTypeFormula),
				LogicalType: string(constants.FieldTypeFormula),
				Formula:     "price * quantity",
			},
			wantErr: true,
			errMsg:  "return_type",
		},
		{
			name: "valid formula field",
			field: schema.ColumnDefinition{
				Name:        "Total",
				Type:        string(constants.FieldTypeFormula),
				LogicalType: string(constants.FieldTypeFormula),
				Formula:     "price * quantity",
				ReturnType:  "double",
			},
			wantErr: false,
		},
		{
			name: "physical type used as logical type bypasses logical validation",
			field: schema.ColumnDefinition{
				Name: "StatusCol",
				Type: "VARCHAR(255)",
				// No LogicalType set, so the switch falls through without picklist/reference checks
			},
			wantErr: false,
		},
		{
			name: "empty field name",
			field: schema.ColumnDefinition{
				Name: "",
				Type: "VARCHAR(255)",
			},
			wantErr: true,
			errMsg:  "must be alphanumeric",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			err := r.ValidateFieldDefinition(tt.field)
			if (err != nil) != tt.wantErr {
				t.Errorf("ValidateFieldDefinition() error = %v, wantErr %v", err, tt.wantErr)
				return
			}
			if tt.wantErr && tt.errMsg != "" {
				if err == nil {
					t.Fatal("expected error but got nil")
				}
				errStr := err.Error()
				if !containsSubstring(errStr, tt.errMsg) {
					t.Errorf("error message %q should contain %q", errStr, tt.errMsg)
				}
			}
		})
	}
}

func containsSubstring(s, sub string) bool {
	return len(s) >= len(sub) && (s == sub || len(s) > 0 && contains(s, sub))
}

func contains(s, sub string) bool {
	for i := 0; i <= len(s)-len(sub); i++ {
		if s[i:i+len(sub)] == sub {
			return true
		}
	}
	return false
}
