package main

import (
	"context"
	"fmt"
	"os"
	"time"

	"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/jsmorgdedupe"
)

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

func newRootCommand() *cobra.Command {
	var configPath string
	var execute bool
	var delay time.Duration

	command := &cobra.Command{
		Use:           "jsm-org-deduper",
		Short:         "Deduplicate and rename TiDB Cloud 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, "JSMOrgDeduperDB")
			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 organizations or database rows will be changed; pass --execute to apply")
			}
			summary, runErr := jsmorgdedupe.Run(
				ctx,
				db,
				atlassian.NewOrganizationMaintenanceClient(conf.Atlassian),
				jsmorgdedupe.Options{
					Execute: execute,
					Delay:   delay,
					Output:  command.OutOrStdout(),
				},
			)
			fmt.Fprintf(
				command.OutOrStdout(),
				"summary scanned=%d succeeded=%d failed=%d duplicates=%d deleted=%d database_writes=%d renamed=%d\n",
				summary.Scanned,
				summary.Succeeded,
				summary.Failed,
				summary.Duplicates,
				summary.Deleted,
				summary.DatabaseWrites,
				summary.Renamed,
			)
			return runErr
		},
	}
	command.Flags().StringVar(&configPath, "config", "", "path to the jsm-syncer root config")
	command.Flags().BoolVar(&execute, "execute", false, "apply destructive JSM and database changes")
	command.Flags().DurationVar(&delay, "delay", 3*time.Second, "delay between the database update and JSM rename")
	_ = 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
}
