package catalogreconcile

import (
	"context"
	"fmt"

	"github.com/nexuscrm/automation/autonumber"
	"github.com/nexuscrm/automation/triggersub"
	"github.com/nexuscrm/db/pkg/connectorreaders"
	"github.com/nexuscrm/kernel/pkg/createsourceguard"
	"github.com/nexuscrm/metadata"
	"github.com/nexuscrm/metadata/catalogsnapshot"
	"github.com/nexuscrm/persistence"
	"github.com/pingcap-inc/nexuscrm-contract/pkg/recordsguard"
	"github.com/pingcap-inc/nexuscrm-controlplane/packs"
)

// RepositoryMetadataReader adapts existing metadata authorities to the one
// Catalog compilation transaction. It owns no fact and keeps no cache: direct
// repository reads are promoted by embedding, while derived accelerators are
// recomputed from their authoritative rows through the transaction executor.
type RepositoryMetadataReader struct {
	*persistence.MetadataRepository
}

func NewRepositoryMetadataReader(repository *persistence.MetadataRepository) (*RepositoryMetadataReader, error) {
	if repository == nil {
		return nil, fmt.Errorf("Catalog metadata repository is required")
	}
	return &RepositoryMetadataReader{MetadataRepository: repository}, nil
}

func (r *RepositoryMetadataReader) GetActiveTriggerSubscriptions(ctx context.Context) ([]catalogsnapshot.TriggerSubscription, error) {
	rows, err := triggersub.ExpectedActiveRows(ctx, r.GetExecutor(ctx))
	if err != nil {
		return nil, err
	}
	result := make([]catalogsnapshot.TriggerSubscription, 0, len(rows))
	for _, row := range rows {
		result = append(result, catalogsnapshot.TriggerSubscription{
			ID: row.Id, KeyPrefix: row.KeyPrefix, EventType: row.EventType,
			RecordTriggerType: row.RecordTriggerType, FlowDefinitionID: row.FlowDefinitionId,
			FlowVersionID: row.FlowVersionId, IsActive: row.IsActive,
		})
	}
	return result, nil
}

func (r *RepositoryMetadataReader) GetAutoNumberRules(ctx context.Context) ([]catalogsnapshot.AutoNumberRule, error) {
	rules, err := autonumber.ReadRules(ctx, r.GetExecutor(ctx))
	if err != nil {
		return nil, err
	}
	result := make([]catalogsnapshot.AutoNumberRule, 0, len(rules))
	for _, rule := range rules {
		value := catalogsnapshot.AutoNumberRule{
			FieldID: rule.FieldID, ObjectAPIName: rule.ObjectAPIName, FieldAPIName: rule.FieldAPIName,
			Format: rule.Format, Start: rule.Start, Scope: rule.Scope,
			DateSource: rule.DateSrc, OnChange: rule.OnChange,
		}
		for _, ref := range rule.TokenRefs {
			converted := catalogsnapshot.AutoNumberTokenRef{
				DirectField: ref.DirectField, ReadStrategy: ref.ReadStrategy,
				TargetField: ref.TargetField, TargetObject: ref.TargetObject, TokenLiteral: ref.TokenLiteral,
				FKChains: make([][]catalogsnapshot.AutoNumberLookupStep, 0, len(ref.FkChains)),
			}
			for _, chain := range ref.FkChains {
				steps := make([]catalogsnapshot.AutoNumberLookupStep, 0, len(chain))
				for _, step := range chain {
					steps = append(steps, catalogsnapshot.AutoNumberLookupStep{
						FK: step.FK, TargetField: step.TargetField, TargetObject: step.TargetObject,
					})
				}
				converted.FKChains = append(converted.FKChains, steps)
			}
			value.TokenRefs = append(value.TokenRefs, converted)
		}
		result = append(result, value)
	}
	return result, nil
}

func (r *RepositoryMetadataReader) GetFieldMappingRules(ctx context.Context) ([]catalogsnapshot.FieldMappingRule, error) {
	rows, err := connectorreaders.GetAllFieldMappingsContext(ctx, r.GetExecutor(ctx))
	if err != nil {
		return nil, err
	}
	result := make([]catalogsnapshot.FieldMappingRule, 0, len(rows))
	for _, row := range rows {
		result = append(result, catalogsnapshot.FieldMappingRule{
			SourceObject: row.SourceObject, TargetObject: row.TargetObject, ActionType: row.ActionType,
			SourceField: row.SourceField, TargetField: row.TargetField,
			DefaultValue: row.DefaultValue, ValueMap: row.ValueMap,
			OnUnmappedValue: row.OnUnmappedValue, SourceLookupField: row.SourceLookupField,
		})
	}
	return result, nil
}

func (r *RepositoryMetadataReader) GetCreateFromSourceGuardEntries(ctx context.Context, targetObject string) ([]recordsguard.CreateFromSourceGuardEntry, error) {
	return createsourceguard.GetCreateFromSourceGuardEntriesContext(ctx, r.GetExecutor(ctx), targetObject)
}

func (r *RepositoryMetadataReader) GetRuntimeRelatedListRules(ctx context.Context) ([]metadata.RelatedListRule, error) {
	return packs.LoadActiveInstalledPersistedRelatedListRulesWithExecutor(ctx, r.GetExecutor(ctx))
}

var _ MetadataReader = (*RepositoryMetadataReader)(nil)
var _ MutationMetadataReader = (*RepositoryMetadataReader)(nil)
var _ PageLayoutResolutionMetadataReader = (*RepositoryMetadataReader)(nil)
