package services

import (
	"context"
	"errors"
	"testing"

	"github.com/nexuscrm/analytics"
	"github.com/nexuscrm/automation/autonumber"
	"github.com/nexuscrm/kernel/pkg/logging"
	"github.com/nexuscrm/kernel/pkg/ports"
	featuremetadata "github.com/nexuscrm/metadata"
	"github.com/nexuscrm/shared/pkg/constants"
	"github.com/nexuscrm/shared/pkg/contract"
	"github.com/nexuscrm/shared/pkg/models"
)

func TestServiceManagerCollectsAllValidationErrorsByDefault(t *testing.T) {
	sm := &ServiceManager{}
	sm.initInfrastructure()

	if !sm.Validation.CollectAllValidationErrorsEnabled() {
		t.Fatal("ServiceManager validation retained the legacy fail-fast default")
	}
}

func TestRefreshAutoNumberMetadataUnavailableWithoutSource(t *testing.T) {
	_, err := (&ServiceManager{}).RefreshAutoNumberMetadata(context.Background())
	var maintenanceErr *contract.MetadataMaintenanceError
	if !errors.As(err, &maintenanceErr) {
		t.Fatalf("RefreshAutoNumberMetadata err = %T %[1]v, want MetadataMaintenanceError", err)
	}
	if maintenanceErr.Kind != contract.MetadataMaintenanceErrorUnavailable {
		t.Fatalf("RefreshAutoNumberMetadata kind = %q, want unavailable", maintenanceErr.Kind)
	}
}

func TestFormulaViewStatusContractCountsStoredActiveFormulaAsFrozenBucket(t *testing.T) {
	activeMode := "active"
	writeMaterialized := "write_materialized"
	rt := models.FieldType(constants.FieldTypeString)
	metadataSvc := featuremetadata.NewMetadataService(&refreshOrderMetadataRepo{
		schemas: []*models.ObjectMetadata{
			{
				APIName: "WorkItem",
				Fields: []models.FieldMetadata{
					{APIName: "Id", Type: constants.FieldTypeString},
					{
						APIName:     "NameEcho",
						Type:        constants.FieldTypeFormula,
						Formula:     maintenanceTestStrPtr("Name"),
						FormulaMode: &activeMode,
						ReturnType:  &rt,
					},
					{
						APIName:            "NameStored",
						Type:               constants.FieldTypeFormula,
						Formula:            maintenanceTestStrPtr("Name"),
						FormulaMode:        &activeMode,
						FormulaStorageMode: &writeMaterialized,
						ReturnType:         &rt,
					},
				},
			},
		},
	}, nil, nil)
	formulaViewSvc := analytics.NewFormulaViewService(nil, metadataSvc, logging.New(context.Background()))
	sm := &ServiceManager{Metadata: metadataSvc, FormulaViewSvc: formulaViewSvc}

	got, err := sm.FormulaViewStatus(context.Background(), "WorkItem")
	if err != nil {
		t.Fatalf("FormulaViewStatus: %v", err)
	}
	if got.ActiveFormulaCount != 1 {
		t.Fatalf("ActiveFormulaCount = %d, want 1", got.ActiveFormulaCount)
	}
	if got.FrozenFormulaCount != 1 {
		t.Fatalf("FrozenFormulaCount = %d, want 1", got.FrozenFormulaCount)
	}
	if got.ResolvedTableName != "v_workitem" {
		t.Fatalf("ResolvedTableName = %q, want v_workitem", got.ResolvedTableName)
	}
}

func TestValidateFormulaViewContractDeepCrossRefReturnsCompiledSQL(t *testing.T) {
	mode := "active"
	rt := models.FieldType(constants.FieldTypeString)
	metadataSvc := featuremetadata.NewMetadataService(&refreshOrderMetadataRepo{
		schemas: []*models.ObjectMetadata{
			{
				APIName: "ObjA",
				Fields: []models.FieldMetadata{
					{APIName: "Id", Type: constants.FieldTypeString},
					{
						APIName:          "OwnerId",
						Type:             constants.FieldTypeReference,
						ReferenceTo:      []string{"User"},
						RelationshipName: maintenanceTestStrPtr("Owner"),
					},
				},
			},
			{
				APIName: "User",
				Fields: []models.FieldMetadata{
					{APIName: "Id", Type: constants.FieldTypeString},
					{
						APIName:          "ProfileId",
						Type:             constants.FieldTypeReference,
						ReferenceTo:      []string{"Profile"},
						RelationshipName: maintenanceTestStrPtr("Profile"),
					},
				},
			},
			{
				APIName: "Profile",
				Fields: []models.FieldMetadata{
					{APIName: "Id", Type: constants.FieldTypeString},
					{APIName: "Name", Type: constants.FieldTypeString},
					{
						APIName:     "DeepDisplay__c",
						Type:        constants.FieldTypeFormula,
						Formula:     maintenanceTestStrPtr("Name"),
						FormulaMode: &mode,
						ReturnType:  &rt,
					},
				},
			},
		},
	}, nil, nil)
	formulaViewSvc := analytics.NewFormulaViewService(nil, metadataSvc, logging.New(context.Background()))
	sm := &ServiceManager{Metadata: metadataSvc, FormulaViewSvc: formulaViewSvc}

	got, err := sm.ValidateFormulaView(context.Background(), contract.FormulaViewValidationRequest{
		ObjectName: "ObjA",
		Formula:    "Owner.Profile.Name",
		ReturnType: "Text",
	})
	if err != nil {
		t.Fatalf("ValidateFormulaView: %v", err)
	}
	if !got.Valid {
		t.Fatalf("Valid = false, want true; error=%q", got.Error)
	}
	if want := "dj_profile.`Name`"; got.CompiledSQL != want {
		t.Fatalf("CompiledSQL = %q, want %q", got.CompiledSQL, want)
	}
}

type refreshAutoNumberEngine struct {
	quarantine *autonumber.QuarantineRegistry
	reconciled bool
}

func (*refreshAutoNumberEngine) AssignOne(context.Context, string, models.SObject) (string, error) {
	return "", nil
}

func (*refreshAutoNumberEngine) PreviewOne(context.Context, string, models.SObject) (string, error) {
	return "", nil
}

func (*refreshAutoNumberEngine) AssignBatch(context.Context, string, []models.SObject) ([]string, error) {
	return nil, nil
}

func (*refreshAutoNumberEngine) SeedFieldCounter(context.Context, string) error {
	return nil
}

func (*refreshAutoNumberEngine) BootstrapField(context.Context, autonumber.Rule) error {
	return nil
}

func (e *refreshAutoNumberEngine) Quarantine() *autonumber.QuarantineRegistry {
	return e.quarantine
}

func (e *refreshAutoNumberEngine) ReconcileQuarantine(context.Context) {
	e.reconciled = true
	e.quarantine.Quarantine("field-name", "test")
}

type refreshOrderMetadataRepo struct {
	ports.MetadataRepository
	schemas []*models.ObjectMetadata
}

func (r *refreshOrderMetadataRepo) GetAllSchemas(context.Context) ([]*models.ObjectMetadata, error) {
	return r.schemas, nil
}

func (r *refreshOrderMetadataRepo) GetAllRelationships(context.Context) ([]*models.Relationship, error) {
	return nil, nil
}

func (r *refreshOrderMetadataRepo) GetAllFlowDefinitions(context.Context) ([]*models.FlowDefinition, error) {
	return nil, nil
}

func (r *refreshOrderMetadataRepo) GetAllValidationRules(context.Context) ([]*models.ValidationRule, error) {
	return nil, nil
}

func maintenanceTestStrPtr(v string) *string { return &v }
