package packs

import (
	"context"
	"encoding/json"
	"fmt"

	"github.com/nexuscrm/metadata"
)

func newSourceBackedSearchScopeOrderComponent(packName string, component ManifestComponent, payload []byte) (PackComponent, []metadata.SearchScopeOrderItem, error) {
	expected, err := searchScopeOrderProjection(payload, componentPayloadLabel(component))
	if err != nil {
		return nil, nil, err
	}
	return newSearchScopeOrderManagedComponentFromItems(packName, component, payload, expected), expected, nil
}

// newSearchScopeOrderManagedComponentFromItems builds the managed component from
// an already-parsed item slice plus the RAW payload bytes and the engine
// ManifestComponent. It is shared by the internal build path and the engine
// implementation of cp.PresentationComponentBuildContext.AddSearchScopeOrderComponent,
// guaranteeing both paths produce a byte-identical component (the payload field is
// the raw bytes, never re-marshalled).
func newSearchScopeOrderManagedComponentFromItems(packName string, component ManifestComponent, payload []byte, expected []metadata.SearchScopeOrderItem) PackComponent {
	return &sourceBackedManagedComponent{
		packName:          packName,
		manifestComponent: component,
		payload:           payload,
		expectedProjection: func() (any, error) {
			return expected, nil
		},
		liveProjection: func(_ context.Context, _ VerifyDeps) (any, error) {
			return expected, nil
		},
		apply: func(_ context.Context, _ ApplyDeps) error {
			return nil
		},
	}
}

func searchScopeOrderProjection(payload []byte, source string) ([]metadata.SearchScopeOrderItem, error) {
	var items []metadata.SearchScopeOrderItem
	if err := json.Unmarshal(payload, &items); err != nil {
		return nil, fmt.Errorf("parse %s: %w", source, err)
	}
	if err := metadata.ValidatePackSearchScopeOrder(items); err != nil {
		return nil, err
	}
	return items, nil
}
