package packs

import (
	"sort"
	"strings"
)

func (p *SourceBackedPack) DeclaredComponents() ([]DeclaredComponent, error) {
	declared := make([]DeclaredComponent, 0, len(p.components))
	for _, component := range p.components {
		converted, err := declaredSourceBackedComponent(component)
		if err != nil {
			return nil, err
		}
		declared = append(declared, converted)
	}
	return declared, nil
}

func declaredSourceBackedComponent(component PackComponent) (DeclaredComponent, error) {
	payload, err := packComponentPayloadBytes(component)
	if err != nil {
		return DeclaredComponent{}, err
	}
	payloadHash := ""
	if len(payload) > 0 {
		canonicalPayload, err := canonicalComponentPayloadForHash(payload)
		if err != nil {
			return DeclaredComponent{}, err
		}
		payloadHash = sha256Hex([]byte(canonicalPayload))
	}
	return DeclaredComponent{
		PackName:      component.PackName(),
		Kind:          component.Kind(),
		BusinessKey:   component.BusinessKey(),
		Required:      true,
		Manageability: component.Manageability(),
		PayloadHash:   payloadHash,
		References:    sourceBackedComponentReferences(component),
	}, nil
}

func sourceBackedComponentReferences(component PackComponent) []ComponentReference {
	provider, ok := component.(ComponentDependencyProvider)
	if !ok {
		return nil
	}
	refs := append([]ComponentReference(nil), provider.DependsOn()...)
	sort.Slice(refs, func(i, j int) bool {
		if refs[i].Kind != refs[j].Kind {
			return refs[i].Kind < refs[j].Kind
		}
		return strings.TrimSpace(refs[i].BusinessKey) < strings.TrimSpace(refs[j].BusinessKey)
	})
	return refs
}
