package services

import (
	"context"
	"fmt"
	"strings"

	"github.com/nexuscrm/shared/pkg/contract"
	"github.com/nexuscrm/shared/pkg/models"
)

type flowCatalogMetadata interface {
	GetFlowDefinitions(ctx context.Context) []*models.FlowDefinition
	GetFlowDefinitionByName(ctx context.Context, developerName string) *models.FlowDefinition
	GetFlowVersionById(ctx context.Context, versionID string) *models.FlowVersion
}

type protectedFlowNamesSource interface {
	ProtectedFlowNames(ctx context.Context) ([]string, error)
}

type flowCatalogContract struct {
	metadata  flowCatalogMetadata
	protected protectedFlowNamesSource
}

var _ contract.FlowCatalog = (*flowCatalogContract)(nil)

func NewFlowCatalogContract(metadata flowCatalogMetadata, protected protectedFlowNamesSource) contract.FlowCatalog {
	return &flowCatalogContract{metadata: metadata, protected: protected}
}

func (c *flowCatalogContract) ProtectedFlowNames(ctx context.Context) ([]string, error) {
	if c == nil || c.protected == nil {
		return nil, fmt.Errorf("protected flow catalog is not configured")
	}
	return c.protected.ProtectedFlowNames(ctx)
}

func (c *flowCatalogContract) ListFlows(ctx context.Context) ([]contract.FlowDescriptor, error) {
	if c == nil || c.metadata == nil {
		return nil, nil
	}
	definitions := c.metadata.GetFlowDefinitions(ctx)
	out := make([]contract.FlowDescriptor, 0, len(definitions))
	for _, def := range definitions {
		if def == nil {
			continue
		}
		out = append(out, flowDescriptorFromModel(def))
	}
	return out, nil
}

func (c *flowCatalogContract) GetFlow(ctx context.Context, flowName string) (*contract.FlowDescriptor, error) {
	if c == nil || c.metadata == nil {
		return nil, nil
	}
	def := c.metadata.GetFlowDefinitionByName(ctx, flowName)
	if def == nil {
		return nil, nil
	}
	descriptor := flowDescriptorFromModel(def)
	return &descriptor, nil
}

func (c *flowCatalogContract) GetFlowRevision(ctx context.Context, revisionID string) (*contract.FlowRevisionDescriptor, error) {
	if c == nil || c.metadata == nil || strings.TrimSpace(revisionID) == "" {
		return nil, nil
	}
	version := c.metadata.GetFlowVersionById(ctx, revisionID)
	if version == nil {
		return nil, nil
	}
	out := contract.FlowRevisionDescriptor{
		Variables: make([]contract.FlowVariableDescriptor, 0, len(version.Metadata.Variables)),
	}
	for _, v := range version.Metadata.Variables {
		out.Variables = append(out.Variables, contract.FlowVariableDescriptor{
			Name:     v.Name,
			DataType: v.DataType,
			IsInput:  v.IsInput,
			IsOutput: v.IsOutput,
		})
	}
	return &out, nil
}

func flowDescriptorFromModel(def *models.FlowDefinition) contract.FlowDescriptor {
	if def == nil {
		return contract.FlowDescriptor{}
	}
	return contract.FlowDescriptor{
		Label:            def.MasterLabel,
		Name:             def.DeveloperName,
		Description:      def.Description,
		ActiveRevisionID: def.ActiveVersionId,
	}
}
