package metadata

import (
	"context"
	"testing"

	"github.com/nexuscrm/kernel/pkg/formula"
	"github.com/nexuscrm/shared/pkg/constants"
	"github.com/nexuscrm/shared/pkg/models"
)

func TestValidateRecordAllowsConfiguredStateTransition(t *testing.T) {
	vs := NewValidationService(formula.NewEngine())
	schema := contractStateTransitionSchema()
	record := models.SObject{"Status": "Activated"}
	oldRecord := models.SObject{"Status": "Draft"}

	if err := vs.ValidateRecord(context.Background(), record, schema, nil, &oldRecord, nil); err != nil {
		t.Fatalf("ValidateRecord allowed transition error = %v, want nil", err)
	}
}

func TestValidateRecordRejectsDisallowedStateTransition(t *testing.T) {
	vs := NewValidationService(formula.NewEngine())
	schema := contractStateTransitionSchema()
	record := models.SObject{"Status": "Draft"}
	oldRecord := models.SObject{"Status": "Activated"}

	if err := vs.ValidateRecord(context.Background(), record, schema, nil, &oldRecord, nil); err == nil {
		t.Fatal("ValidateRecord disallowed transition error = nil, want rejection")
	}
}

func TestValidateRecordRejectsBlankPriorStateTransition(t *testing.T) {
	vs := NewValidationService(formula.NewEngine())
	schema := contractStateTransitionSchema()
	record := models.SObject{"Status": "Activated"}
	oldRecord := models.SObject{"Status": ""}

	if err := vs.ValidateRecord(context.Background(), record, schema, nil, &oldRecord, nil); err == nil {
		t.Fatal("ValidateRecord blank prior transition error = nil, want rejection")
	}
}

func TestValidateRecordRejectsDisallowedInitialStateTransition(t *testing.T) {
	vs := NewValidationService(formula.NewEngine())
	schema := contractStateTransitionSchema()
	record := models.SObject{"Status": "Activated"}

	if err := vs.ValidateRecord(context.Background(), record, schema, nil, nil, nil); err == nil {
		t.Fatal("ValidateRecord initial activated state error = nil, want rejection")
	}
}

func TestValidateRecordReactivationConstraintsAllowsKnownNonInitialState(t *testing.T) {
	vs := NewValidationService(formula.NewEngine())
	schema := contractStateTransitionSchema()
	record := models.SObject{"Status": "Activated"}

	if err := vs.ValidateRecordReactivationConstraints(record, schema); err != nil {
		t.Fatalf("ValidateRecordReactivationConstraints activated state error = %v, want nil", err)
	}
}

func TestValidateRecordReactivationConstraintsAllowsTargetOnlyState(t *testing.T) {
	vs := NewValidationService(formula.NewEngine())
	validator := "state_transition"
	config := `{"initial":["Draft"],"transitions":{"Draft":["Closed"]}}`
	schema := &models.ObjectMetadata{
		APIName: "Contract",
		Fields: []models.FieldMetadata{{
			APIName:         "Status",
			Type:            constants.FieldTypePicklist,
			Validator:       &validator,
			ValidatorConfig: &config,
		}},
	}
	record := models.SObject{"Status": "Closed"}

	if err := vs.ValidateRecordReactivationConstraints(record, schema); err != nil {
		t.Fatalf("ValidateRecordReactivationConstraints target-only state error = %v, want nil", err)
	}
}

func TestValidateRecordReactivationConstraintsAllowsRetiredStaticPicklistValue(t *testing.T) {
	vs := NewValidationService(formula.NewEngine())
	schema := &models.ObjectMetadata{
		APIName: "WorkItem",
		Fields: []models.FieldMetadata{{
			APIName: "Category", Type: constants.FieldTypePicklist,
			Options: models.PicklistOptionsFromStrings([]string{"Current"}),
		}},
	}
	record := models.SObject{"Category": "Retired"}

	if err := vs.ValidateRecordReactivationConstraintsWithStoredRecord(record, record, schema); err != nil {
		t.Fatalf("retired stored picklist value = %v, want nil", err)
	}
}

func TestValidateRecordReactivationConstraintsWithoutStoredImageRemainsStrict(t *testing.T) {
	vs := NewValidationService(formula.NewEngine())
	schema := &models.ObjectMetadata{
		APIName: "WorkItem",
		Fields: []models.FieldMetadata{{
			APIName: "Category", Type: constants.FieldTypePicklist,
			Options: models.PicklistOptionsFromStrings([]string{"Current"}),
		}},
	}

	if err := vs.ValidateRecordReactivationConstraints(models.SObject{"Category": "Retired"}, schema); err == nil {
		t.Fatal("reactivation without a stored image grandfathered an invalid picklist value")
	}
}

func TestValidateRecordReactivationConstraintsRejectsNewRetiredStaticPicklistValue(t *testing.T) {
	vs := NewValidationService(formula.NewEngine())
	schema := &models.ObjectMetadata{
		APIName: "WorkItem",
		Fields: []models.FieldMetadata{{
			APIName: "Category", Type: constants.FieldTypePicklist,
			Options: models.PicklistOptionsFromStrings([]string{"Current"}),
		}},
	}
	stored := models.SObject{"Category": "Current"}
	final := models.SObject{"Category": "Retired"}

	if err := vs.ValidateRecordReactivationConstraintsWithStoredRecord(final, stored, schema); err == nil {
		t.Fatal("new retired picklist value was accepted")
	}
}

func TestValidateRecordReactivationConstraintsRejectsStateMissingFromCurrentGraph(t *testing.T) {
	vs := NewValidationService(formula.NewEngine())
	schema := contractStateTransitionSchema()
	record := models.SObject{"Status": "Retired"}

	if err := vs.ValidateRecordReactivationConstraints(record, schema); err == nil {
		t.Fatal("ValidateRecordReactivationConstraints missing graph state error = nil, want rejection")
	}
}

func TestValidateFieldMetadataRejectsMalformedStateTransitionConfig(t *testing.T) {
	vs := NewValidationService(formula.NewEngine())
	validator := "state_transition"
	badConfig := `{"initial":["Draft"]`
	field := &models.FieldMetadata{
		APIName:         "Status",
		Type:            constants.FieldTypePicklist,
		Validator:       &validator,
		ValidatorConfig: &badConfig,
	}

	if err := vs.ValidateFieldMetadata(field); err == nil {
		t.Fatal("ValidateFieldMetadata malformed config error = nil, want rejection")
	}
}

func contractStateTransitionSchema() *models.ObjectMetadata {
	validator := "state_transition"
	config := `{"initial":["Draft"],"transitions":{"Draft":["InApproval","Activated"],"InApproval":["Activated"],"Activated":["Effective","Expired","Terminated"],"Effective":["Expired","Terminated"],"Expired":[],"Terminated":[]}}`
	return &models.ObjectMetadata{
		APIName: "Contract",
		Fields: []models.FieldMetadata{
			{
				APIName:         "Status",
				Type:            constants.FieldTypePicklist,
				Validator:       &validator,
				ValidatorConfig: &config,
			},
		},
	}
}
