package provision

import (
	"context"
	"fmt"

	"sub2api-cn-relay-manager/internal/host/sub2api"
	"sub2api-cn-relay-manager/internal/pack"
)

const (
	PreviewActionCreate   = "create"
	PreviewActionReuse    = "reuse"
	PreviewActionConflict = "conflict"
)

type previewHost interface {
	ListManagedResources(ctx context.Context, req sub2api.ListManagedResourcesRequest) (sub2api.ManagedResourceSnapshot, error)
}

type PreviewRequest struct {
	TargetHost  string
	HostVersion string
	Provider    pack.ProviderManifest
	Mode        string
	Keys        []string
}

type PreviewDecision struct {
	Action     string
	Suggested  string
	ExistingID string
	Reason     string
}

type PreviewReport struct {
	AcceptedKeys []string
	HostOverlays []pack.HostOverlay
	Names        ResourceNames
	Decisions    map[string]PreviewDecision
}

type PreviewService struct {
	host previewHost
}

func NewPreviewService(host previewHost) *PreviewService {
	return &PreviewService{host: host}
}

func (s *PreviewService) PreviewImport(ctx context.Context, req PreviewRequest) (PreviewReport, error) {
	acceptedKeys, err := normalizeKeys(req.Keys)
	if err != nil {
		return PreviewReport{}, err
	}
	if err := validateMode(req.Mode); err != nil {
		return PreviewReport{}, err
	}
	if s.host == nil {
		return PreviewReport{}, fmt.Errorf("preview host is required")
	}
	hostOverlays, err := pack.ResolveApplicableHostOverlays(req.Provider, req.TargetHost, req.HostVersion)
	if err != nil {
		return PreviewReport{}, fmt.Errorf("resolve host overlays: %w", err)
	}

	names := SuggestResourceNamesForMode(req.Provider, req.Mode)
	snapshot, err := s.host.ListManagedResources(ctx, sub2api.ListManagedResourcesRequest{
		GroupName:         names.Group,
		ChannelName:       names.Channel,
		PlanName:          names.Plan,
		AccountNamePrefix: SuggestAccountNamePrefix(req.Provider),
	})
	if err != nil {
		return PreviewReport{}, fmt.Errorf("list managed resources: %w", err)
	}

	return PreviewReport{
		AcceptedKeys: acceptedKeys,
		HostOverlays: hostOverlays,
		Names:        names,
		Decisions: map[string]PreviewDecision{
			"group":   decideResource(names.Group, snapshot.Groups),
			"channel": decideResource(names.Channel, snapshot.Channels),
			"plan":    decideResource(names.Plan, snapshot.Plans),
		},
	}, nil
}

func decideResource(suggested string, existing []sub2api.NamedResource) PreviewDecision {
	switch len(existing) {
	case 0:
		return PreviewDecision{Action: PreviewActionCreate, Suggested: suggested}
	case 1:
		return PreviewDecision{Action: PreviewActionReuse, Suggested: suggested, ExistingID: existing[0].ID, Reason: "matching managed resource already exists"}
	default:
		return PreviewDecision{Action: PreviewActionConflict, Suggested: suggested, Reason: "multiple managed resources share the suggested name"}
	}
}
