package cli

import (
	"strings"

	"github.com/spf13/cobra"

	"github.com/tidbcloud/observability/vm-migration/internal/tenants"
)

// newTenantsEssentialCmd returns the tenants essential command group: the
// Essential collection pipeline, one stage per subcommand.
//
// Stage artifacts chain as essential-mgmt.json → essential-rds.json →
// tenants-essential.json; run each stage in an environment that reaches its
// system.
func newTenantsEssentialCmd() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "essential",
		Short: "Collect Essential-tier tenants in stages (mgmt, rds, s3)",
		Long: `Collects Essential-tier tenants in three stages, one system each:
  mgmt  ListClusters (region/provider-filtered, Essential plan, both deletion
        states, merged by clusterId, liveness-filtered by --max-age) —
        writes the cluster report
  rds   join alive clusters against the regional-server MySQL by
        application_id to attach vm account/project ids — writes the
        enriched cluster report
  s3    resolve deleted clusters from archived cluster.yaml, merge with the
        alive clusters' tenants — writes the complete tenants JSON

Each stage runs where its system is reachable; copy artifacts between
environments. Both endpoints are insecure-internal: port-forward the mgmt
gRPC service to --addr and the regional-server MySQL (host:3306 from the
secret) to --db-host.

Save the RDS secret first:
  aws secretsmanager get-secret-value --secret-id <arn> --region <region> \
    --query SecretString --output text > rds_region.json`,
		Example: `  # stage 1 (environment reaching mgmt):
  vm-migration tenants essential mgmt \
    --addr <addr> \
    --region <region> \
    --provider <provider> \
    --output essential-mgmt.json

  # stage 2 (environment reaching the regional DB):
  vm-migration tenants essential rds \
    --clusters-in essential-mgmt.json \
    --secret-file <secret-file> \
    --db-host <db-host> \
    --output essential-rds.json

  # stage 3 (environment reaching S3) — output feeds tenants merge:
  vm-migration tenants essential s3 \
    --clusters-in essential-rds.json \
    --s3-bucket <bucket> \
    --output tenants-essential.json`,
		Args:         cobra.NoArgs,
		SilenceUsage: true,
	}
	cmd.AddCommand(
		newTenantsEssentialMgmtCmd(),
		newTenantsEssentialRdsCmd(),
		newTenantsEssentialS3Cmd(),
	)
	return cmd
}

// newTenantsEssentialMgmtCmd returns stage 1: the mgmt listing.
func newTenantsEssentialMgmtCmd() *cobra.Command {
	var o tenants.EssentialMgmtOptions
	o.MaxAge = tenants.DefaultMaxAge
	o.Timeout = tenants.DefaultEssentialTimeout
	cmd := &cobra.Command{
		Use:   "mgmt",
		Short: "Stage 1: list Essential clusters from mgmt",
		Long: `Lists Essential-plan clusters from the mgmt gRPC API (region and
provider filtered, both deletion states, merged by clusterId), keeps deleted
clusters deleted within --max-age, and writes the cluster report that feeds
` + "`tenants essential rds`" + `.`,
		Example: `  # one-time prep: expose the mgmt gRPC service on localhost:10001
  # (cleanup when done: kubectl delete pod -n observability mgmt-proxy):
  kubectl run -n observability mgmt-proxy --image=alpine/socat --restart=Never -- \
    TCP-LISTEN:10001,fork,reuseaddr TCP:tidb-mgmt-svc-grpc:10001
  kubectl port-forward -n observability pod/mgmt-proxy 10001:10001

  vm-migration tenants essential mgmt \
    --addr 127.0.0.1:10001 \
    --region <region> \
    --provider <provider> \
    --output essential-mgmt.json`,
		Args:         cobra.NoArgs,
		SilenceUsage: true,
		RunE: func(cmd *cobra.Command, args []string) error {
			lister, closer, err := tenants.NewMgmtLister(o.Addr)
			if err != nil {
				return err
			}
			defer func() { _ = closer() }()
			return tenants.RunEssentialMgmt(
				cmd.Context(),
				o,
				lister,
				cmd.OutOrStdout(),
				cmd.ErrOrStderr(),
			)
		},
	}
	cmd.Flags().StringVar(&o.Addr, "addr", "", "mgmt gRPC service address host:port, port-forwarded (required)")
	cmd.Flags().StringVar(&o.Region, "region", "", "region filter (required)")
	cmd.Flags().StringVar(&o.Provider, "provider", "", "cloud provider filter: "+strings.Join(tenants.EssentialProviders, ", ")+" (required)")
	cmd.Flags().StringVar(&o.MaxAge, "max-age", o.MaxAge, "Keep deleted clusters deleted within last N days (e.g. 30d)")
	cmd.Flags().DurationVar(&o.Timeout, "timeout", o.Timeout, "Overall collection timeout")
	cmd.Flags().StringVar(&o.Output, "output", "", "Output cluster report JSON path (default: stdout)")
	mustMarkRequired(cmd, "addr")
	mustMarkRequired(cmd, "region")
	mustMarkRequired(cmd, "provider")
	return cmd
}

// newTenantsEssentialRdsCmd returns stage 2: the regional-server join.
func newTenantsEssentialRdsCmd() *cobra.Command {
	var o tenants.EssentialRdsOptions
	o.Timeout = tenants.DefaultEssentialTimeout
	cmd := &cobra.Command{
		Use:   "rds",
		Short: "Stage 2: join alive clusters with regional-server vm ids",
		Long: `Loads the mgmt-stage cluster report, joins alive clusters against
the regional-server MySQL (serverless schema) by application_id to attach
vm_account_id / vm_project_id, and writes the enriched report that feeds
` + "`tenants essential s3`" + `.

--db-host overrides the secret-file host for port-forwarded access.`,
		Example: `  # one-time prep: expose the regional RDS endpoint on localhost:3306 —
  # <rds-host> is the host field of the --secret-file JSON; the pod
  # self-cleans on interrupt via --rm:
  kubectl run rds-proxy --rm -i --tty --wait -n observability \
    --image=alpine/socat --restart=Never -- \
    TCP-LISTEN:3306,fork,reuseaddr TCP:<rds-host>:3306
  kubectl port-forward -n observability pod/rds-proxy 3306:3306

  vm-migration tenants essential rds \
    --clusters-in essential-mgmt.json \
    --secret-file <secret-file> \
    --db-host 127.0.0.1 \
    --output essential-rds.json`,
		Args:         cobra.NoArgs,
		SilenceUsage: true,
		RunE: func(cmd *cobra.Command, args []string) error {
			if err := o.Validate(); err != nil {
				return err
			}
			dbCfg, err := tenants.ResolveMySQLConfig(o)
			if err != nil {
				return err
			}
			querier, dbClose, err := tenants.NewMySQLQuerier(cmd.Context(), dbCfg)
			if err != nil {
				return err
			}
			defer func() { _ = dbClose() }()
			return tenants.RunEssentialRds(
				cmd.Context(),
				o,
				querier,
				cmd.OutOrStdout(),
				cmd.ErrOrStderr(),
			)
		},
	}
	cmd.Flags().StringVar(&o.ClustersIn, "clusters-in", "", "Cluster report JSON from tenants essential mgmt (required)")
	cmd.Flags().StringVar(&o.SecretFile, "secret-file", "", "RDS secret JSON path with host/port/username/password/dbname (required)")
	cmd.Flags().StringVar(&o.DBHost, "db-host", "", "MySQL host; overrides the secret-file host (port-forward case)")
	cmd.Flags().BoolVar(&o.TLS, "tls", false, "Use TLS for the MySQL connection (tls=skip-verify)")
	cmd.Flags().DurationVar(&o.Timeout, "timeout", o.Timeout, "Overall collection timeout")
	cmd.Flags().StringVar(&o.Output, "output", "", "Output enriched cluster report JSON path (default: stdout)")
	mustMarkRequired(cmd, "clusters-in")
	mustMarkRequired(cmd, "secret-file")
	return cmd
}

// newTenantsEssentialS3Cmd returns stage 3: archive resolution and the
// final Essential tenants list.
func newTenantsEssentialS3Cmd() *cobra.Command {
	var o tenants.EssentialS3Options
	o.Timeout = tenants.DefaultEssentialS3Timeout
	cmd := &cobra.Command{
		Use:   "s3",
		Short: "Stage 3: resolve deleted clusters from S3, emit the tenants list",
		Long: `Loads the rds-stage enriched report, resolves deleted clusters'
tenants from archived cluster.yaml in the bucket (one exact-key aws s3 cp per
cluster), merges them with the alive clusters' tenants, and writes the
complete Essential tenants JSON — one tenants merge --input.`,
		Example: `  vm-migration tenants essential s3 \
    --clusters-in essential-rds.json \
    --s3-bucket <bucket> \
    --output tenants-essential.json`,
		Args:         cobra.NoArgs,
		SilenceUsage: true,
		RunE: func(cmd *cobra.Command, args []string) error {
			return tenants.RunEssentialS3(
				cmd.Context(),
				o,
				tenants.NewAWSCLIFetcher(),
				cmd.OutOrStdout(),
				cmd.ErrOrStderr(),
			)
		},
	}
	cmd.Flags().StringVar(&o.ClustersIn, "clusters-in", "", "Enriched cluster report JSON from tenants essential rds (required)")
	cmd.Flags().StringVar(&o.S3Bucket, "s3-bucket", "", "Resolve deleted clusters' tenants from archived cluster.yaml in this bucket (required)")
	cmd.Flags().DurationVar(&o.Timeout, "timeout", o.Timeout, "Overall collection timeout")
	cmd.Flags().StringVar(&o.Output, "output", "", "Output tenants JSON path (default: stdout)")
	mustMarkRequired(cmd, "clusters-in")
	mustMarkRequired(cmd, "s3-bucket")
	return cmd
}
