package services

import (
	"context"
	"strings"
	"testing"

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

func TestMetadataMaintenanceValidateFormulaSelfRefActiveComputedReturnsValid(t *testing.T) {
	mode := "active"
	rt := models.FieldType(constants.FieldTypeString)
	sm := newFormulaMaintenanceServiceManager(map[string]*models.ObjectMetadata{
		"obja": {
			APIName: "ObjA",
			Fields: []models.FieldMetadata{
				{APIName: "Id", Type: constants.FieldTypeString},
				{
					APIName:          "ParentId",
					Type:             constants.FieldTypeReference,
					ReferenceTo:      []string{"ObjA"},
					RelationshipName: formulaMaintenanceStrPtr("Parent"),
				},
				{
					APIName:     "ComputedX__c",
					Type:        constants.FieldTypeFormula,
					Formula:     formulaMaintenanceStrPtr("'computed'"),
					FormulaMode: &mode,
					ReturnType:  &rt,
				},
			},
		},
	})

	resp, err := sm.ValidateFormulaView(context.Background(), contract.FormulaViewValidationRequest{
		ObjectName: "ObjA",
		Formula:    "Parent.ComputedX__c",
		ReturnType: "Text",
	})
	if err != nil {
		t.Fatalf("ValidateFormulaView: %v", err)
	}
	if resp == nil || !resp.Valid {
		t.Fatalf("ValidateFormulaView valid = false, want true; resp=%+v", resp)
	}
}

func TestMetadataMaintenanceFormulaViewStatusCountsStoredActiveFormulaAsFrozenBucket(t *testing.T) {
	activeMode := "active"
	writeMaterialized := "write_materialized"
	rt := models.FieldType(constants.FieldTypeString)
	sm := newFormulaMaintenanceServiceManager(map[string]*models.ObjectMetadata{
		"workitem": {
			APIName: "WorkItem",
			Fields: []models.FieldMetadata{
				{APIName: "Id", Type: constants.FieldTypeString},
				{
					APIName:     "NameEcho",
					Type:        constants.FieldTypeFormula,
					Formula:     formulaMaintenanceStrPtr("Name"),
					FormulaMode: &activeMode,
					ReturnType:  &rt,
				},
				{
					APIName:            "NameStored",
					Type:               constants.FieldTypeFormula,
					Formula:            formulaMaintenanceStrPtr("Name"),
					FormulaMode:        &activeMode,
					FormulaStorageMode: &writeMaterialized,
					ReturnType:         &rt,
				},
			},
		},
	})

	resp, err := sm.FormulaViewStatus(context.Background(), "WorkItem")
	if err != nil {
		t.Fatalf("FormulaViewStatus: %v", err)
	}
	if resp.ActiveFormulaCount != 1 {
		t.Fatalf("ActiveFormulaCount = %d, want 1", resp.ActiveFormulaCount)
	}
	if resp.FrozenFormulaCount != 1 {
		t.Fatalf("FrozenFormulaCount = %d, want 1 for write_materialized active formula bucket", resp.FrozenFormulaCount)
	}
}

func TestMetadataMaintenanceValidateFormulaSelfEditActiveComputedReturnsInvalid(t *testing.T) {
	mode := "active"
	rt := models.FieldType(constants.FieldTypeString)
	sm := newFormulaMaintenanceServiceManager(map[string]*models.ObjectMetadata{
		"obja": {
			APIName: "ObjA",
			Fields: []models.FieldMetadata{
				{APIName: "Id", Type: constants.FieldTypeString},
				{
					APIName:          "ParentId",
					Type:             constants.FieldTypeReference,
					ReferenceTo:      []string{"ObjA"},
					RelationshipName: formulaMaintenanceStrPtr("Parent"),
				},
				{
					APIName:     "ComputedX__c",
					Type:        constants.FieldTypeFormula,
					Formula:     formulaMaintenanceStrPtr("'computed'"),
					FormulaMode: &mode,
					ReturnType:  &rt,
				},
			},
		},
	})

	resp, err := sm.ValidateFormulaView(context.Background(), contract.FormulaViewValidationRequest{
		ObjectName:   "ObjA",
		Formula:      "Parent.ComputedX__c",
		FieldAPIName: "ComputedX__c",
		ReturnType:   "Text",
	})
	if err != nil {
		t.Fatalf("ValidateFormulaView: %v", err)
	}
	if resp == nil {
		t.Fatal("ValidateFormulaView response = nil")
	}
	if resp.Valid {
		t.Fatalf("Valid = true, want false; resp=%+v", resp)
	}
	if !strings.Contains(resp.Error, "circular dependency") {
		t.Fatalf("Error = %q, want circular dependency", resp.Error)
	}
}

func TestMetadataMaintenanceValidateFormulaUnknownCrossRefReturnsInvalid(t *testing.T) {
	sm := newFormulaMaintenanceServiceManager(map[string]*models.ObjectMetadata{
		"obja": {
			APIName: "ObjA",
			Fields: []models.FieldMetadata{
				{APIName: "Id", Type: constants.FieldTypeString},
			},
		},
	})

	resp, err := sm.ValidateFormulaView(context.Background(), contract.FormulaViewValidationRequest{
		ObjectName: "ObjA",
		Formula:    "Parent.ComputedX__c",
		ReturnType: "Text",
	})
	if err != nil {
		t.Fatalf("ValidateFormulaView: %v", err)
	}
	if resp == nil {
		t.Fatal("ValidateFormulaView response = nil")
	}
	if resp.Valid {
		t.Fatalf("Valid = true, want false; resp=%+v", resp)
	}
	if !strings.Contains(resp.Error, "missing metadata join") {
		t.Fatalf("Error = %q, want missing metadata join", resp.Error)
	}
}

func TestMetadataMaintenanceValidateFormulaDeepCrossRefReturnsCompiledSQL(t *testing.T) {
	mode := "active"
	rt := models.FieldType(constants.FieldTypeString)
	sm := newFormulaMaintenanceServiceManager(map[string]*models.ObjectMetadata{
		"obja": {
			APIName: "ObjA",
			Fields: []models.FieldMetadata{
				{APIName: "Id", Type: constants.FieldTypeString},
				{
					APIName:          "OwnerId",
					Type:             constants.FieldTypeReference,
					ReferenceTo:      []string{"User"},
					RelationshipName: formulaMaintenanceStrPtr("Owner"),
				},
			},
		},
		"user": {
			APIName: "User",
			Fields: []models.FieldMetadata{
				{APIName: "Id", Type: constants.FieldTypeString},
				{
					APIName:          "ProfileId",
					Type:             constants.FieldTypeReference,
					ReferenceTo:      []string{"Profile"},
					RelationshipName: formulaMaintenanceStrPtr("Profile"),
				},
			},
		},
		"profile": {
			APIName: "Profile",
			Fields: []models.FieldMetadata{
				{APIName: "Id", Type: constants.FieldTypeString},
				{APIName: "Name", Type: constants.FieldTypeString},
				{
					APIName:     "DeepDisplay__c",
					Type:        constants.FieldTypeFormula,
					Formula:     formulaMaintenanceStrPtr("Name"),
					FormulaMode: &mode,
					ReturnType:  &rt,
				},
			},
		},
	})

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

func newFormulaMaintenanceServiceManager(schemas map[string]*models.ObjectMetadata) *ServiceManager {
	metadataSvc := featuremetadata.NewMetadataService(&formulaMaintenanceMetadataRepo{
		schemas: schemas,
	}, nil, nil)
	formulaViewSvc := analytics.NewFormulaViewService(nil, metadataSvc, logging.New(context.Background()))
	return &ServiceManager{
		Metadata:       metadataSvc,
		FormulaViewSvc: formulaViewSvc,
	}
}

type formulaMaintenanceMetadataRepo struct {
	ports.MetadataRepository
	schemas map[string]*models.ObjectMetadata
}

func (r *formulaMaintenanceMetadataRepo) GetAllSchemas(context.Context) ([]*models.ObjectMetadata, error) {
	out := make([]*models.ObjectMetadata, 0, len(r.schemas))
	for _, schema := range r.schemas {
		out = append(out, schema)
	}
	return out, nil
}

func (r *formulaMaintenanceMetadataRepo) GetSchemaByAPIName(_ context.Context, apiName string) (*models.ObjectMetadata, error) {
	for name, schema := range r.schemas {
		if strings.EqualFold(name, apiName) || strings.EqualFold(schema.APIName, apiName) {
			return schema, nil
		}
	}
	return nil, nil
}

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

func (*formulaMaintenanceMetadataRepo) GetRecordTypes(context.Context, string) ([]*models.RecordType, error) {
	return nil, nil
}

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