package crd

import (
	"context"
	"fmt"

	"github.com/tidbcloud/controlplane9/internal/cluster"
	"github.com/tidbcloud/controlplane9/internal/config"
	"github.com/tidbcloud/controlplane9/internal/host"
)

// InstallStep implements cluster.Step for the crd_install phase.
// It dumps CRDs from staging and applies them to the selected host cluster
// (local or remote), then injects secrets from cp9.local.yaml.
type InstallStep struct {
	// StepName is the lifecycle state this invocation represents.
	StepName cluster.StepName
	// Services is the list of controller services with CRD mappings.
	Services []string
	// CRDMappings maps service name → CRD API group mapping.
	CRDMappings map[string]config.CRDMapping
	// Secrets maps service name → secret source.
	Secrets map[string]config.SecretSource
	// Namespace is the target namespace.
	Namespace string
	// SeedConfig from cp9.yaml crds.seed section.
	SeedConfig config.CRDSeedConfig
	// StateDir for dump caching.
	StateDir string
	// StagingKubeconfig is the path to the staging kubeconfig.
	StagingKubeconfig string
	// StagingContext is the kubectl context for staging.
	StagingContext string
	// LocalKubeconfig is the kubeconfig path for the selected host.
	LocalKubeconfig string
	// LocalContext is the kubectl context for the selected host cluster.
	LocalContext string
	// Selected is the selected host session, used when kubectl must execute remotely.
	Selected *host.Session
}

func (s *InstallStep) Name() cluster.StepName {
	if s.StepName == "" {
		return cluster.StepCRDInstall
	}
	return s.StepName
}

func (s *InstallStep) Run(ctx context.Context) error {
	// Skip if no CRD mappings and no secrets.
	if len(s.CRDMappings) == 0 && len(s.Secrets) == 0 {
		return nil
	}

	result := Run(ctx, &Options{
		Services:    s.Services,
		CRDMappings: s.CRDMappings,
		Secrets:     s.Secrets,
		Namespace:   s.Namespace,
		SeedConfig:  s.SeedConfig,
		StateDir:    s.StateDir,
		Dumper: &Dumper{
			Kubeconfig: s.StagingKubeconfig,
			Context:    s.StagingContext,
		},
		Applier: &Applier{
			Kubeconfig: s.LocalKubeconfig,
			Context:    s.LocalContext,
			Selected:   s.Selected,
		},
	})

	for _, svc := range result.Services {
		if svc.Status == "failed" {
			return fmt.Errorf("CRD install failed for %s: %s", svc.Service, svc.Error)
		}
	}

	for _, sec := range result.Secrets {
		if sec.Status == "failed" {
			return fmt.Errorf("secret injection failed for %s: %s", sec.Service, sec.Error)
		}
	}

	return nil
}
