package main

import (
	"context"
	"fmt"
	"os"

	"github.com/spf13/cobra"

	infcfg "github.com/tidbcloud/aisupport/packages/sdk-go/infra/config"
	"github.com/tidbcloud/aisupport/packages/sdk-go/infra/config/loader"
	sdkdatabase "github.com/tidbcloud/aisupport/packages/sdk-go/infra/database"
	"github.com/tidbcloud/aisupport/packages/sdk-go/infra/logger"
	"github.com/tidbcloud/aisupport/packages/sdk-go/infra/utils/signals"
	"github.com/tidbcloud/aisupport/services/jsm-syncer/config"
	"github.com/tidbcloud/aisupport/services/jsm-syncer/internal/integrations/atlassian"
	"github.com/tidbcloud/aisupport/services/jsm-syncer/internal/maintenance/mspmembersync"
)

func main() {
	if err := newRootCommand().Execute(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

func newRootCommand() *cobra.Command {
	var configPath string
	var customerOrgID string
	var execute bool

	command := &cobra.Command{
		Use:           "jsm-msp-member-syncer",
		Short:         "Add MSP members to related customer JSM organizations",
		SilenceErrors: true,
		SilenceUsage:  true,
		RunE: func(command *cobra.Command, _ []string) error {
			ctx := signals.SetupSignalHandler()
			conf, err := loadConfig(ctx, configPath)
			if err != nil {
				return err
			}
			if err := logger.InitLogger(&conf.Log); err != nil {
				return fmt.Errorf("initialize logger: %w", err)
			}

			db, err := sdkdatabase.Connect(conf.Database, "JSMMSPMemberSyncerDB")
			if err != nil {
				return err
			}
			sqlDB, err := db.DB()
			if err != nil {
				return fmt.Errorf("get SQL database handle: %w", err)
			}
			defer sqlDB.Close()

			if !execute {
				fmt.Fprintln(command.OutOrStdout(), "DRY RUN: no JSM organization members will be added; pass --execute to apply")
			}
			summary, runErr := mspmembersync.Run(
				ctx,
				db,
				atlassian.NewClient(conf.Atlassian),
				mspmembersync.Options{
					Execute:       execute,
					CustomerOrgID: customerOrgID,
					Output:        command.OutOrStdout(),
				},
			)
			fmt.Fprintf(
				command.OutOrStdout(),
				"summary customer_orgs_scanned=%d succeeded=%d failed=%d missing_jsm=%d msp_members_scanned=%d missing_account_id=%d already_present=%d additions_planned=%d added=%d\n",
				summary.CustomerOrgsScanned,
				summary.CustomerOrgsSucceeded,
				summary.CustomerOrgsFailed,
				summary.CustomerOrgsMissingJSM,
				summary.MSPMembersScanned,
				summary.MSPMembersMissingAccount,
				summary.MSPMembersAlreadyPresent,
				summary.MSPMemberAdditionsPlanned,
				summary.MSPMembersAdded,
			)
			return runErr
		},
	}
	command.Flags().StringVar(&configPath, "config", "", "path to the jsm-syncer root config")
	command.Flags().StringVar(&customerOrgID, "customer-org-id", "", "only sync one TiDB Cloud customer organization")
	command.Flags().BoolVar(&execute, "execute", false, "add missing MSP members to customer JSM organizations")
	_ = command.MarkFlagRequired("config")
	return command
}

func loadConfig(ctx context.Context, configPath string) (*config.RootConfig, error) {
	confSources := []loader.ConfigurationSource[config.RootConfig]{
		loader.NewConfigurationSourceDefault[config.RootConfig](),
		loader.NewConfigurationSourceFile[config.RootConfig](configPath),
		loader.NewConfigurationSourceSecret(func(pre *config.RootConfig) (string, infcfg.Secret) {
			return pre.Secret.RootConfigSecretName, pre.Secret.Secret
		}),
	}
	conf, err := loader.NewConfigurationLoader(confSources, false).Load(ctx)
	if err != nil {
		return nil, fmt.Errorf("load config: %w", err)
	}
	return conf, nil
}
