// Fix blank org names
// To compile: GO111MODULE=on CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-s -w " -v -o fix_blank ./main.go
package main

import (
	"context"
	"flag"
	"fmt"

	"github.com/tidbcloud/account/commons/database"

	"github.com/tidbcloud/account/central/server"
	"github.com/tidbcloud/account/central/utils"
	"github.com/tidbcloud/account/commons/config"
	"github.com/tidbcloud/account/internel/dao"
	"github.com/tidbcloud/account/internel/dao/entity"
	"github.com/tidbcloud/account/internel/dao/org"
	grpc_errcode "github.com/tidbcloud/account/pkg/grpc/middleware/errcode"
	"github.com/tidbcloud/tiinf/monitor/tilog"
	"go.uber.org/zap"
	"gorm.io/gorm"
)

const (
	defaultConfigPath = "/etc/dbaas/config.yaml"
)

func RenameOrg(ctx context.Context, tx *gorm.DB, org entity.Tenant, newName string) error {
	org.Name = newName
	return org.Update(tx, entity.TenantDBSchema.Name)
}

func GetNewOrgName(ctx context.Context, tx *gorm.DB, org entity.Tenant) (string, error) {
	daoHub := dao.NewDaoHub()

	orgName := "Org 1"
	user, err := daoHub.User.GetUserByEmail(ctx, tx, org.Email)
	if err != nil && err != gorm.ErrRecordNotFound {
		return "", err
	}
	if user != nil {
		firstName := user.FirstName
		if firstName != "" {
			orgName = fmt.Sprintf("%s's Org", firstName)
		}
	}

	return orgName, nil
}

func ListOrgsWithBlankNames(ctx context.Context, tx *gorm.DB) ([]entity.Tenant, error) {
	var result []entity.Tenant

	daoHub := dao.NewDaoHub()

	resp, err := daoHub.Org.ListOrgs(
		ctx, tx, org.ListOrgsParam{
			Filter: org.ListOrgsFilter{
				Status: []string{
					string(entity.TenantStatusActive),
					string(entity.TenantStatusPending),
				},
			},
		},
	)
	if err != nil {
		return nil, err
	}

	orgs := resp.List
	for _, org := range orgs {
		if org.Name == "" {
			result = append(result, org)
		}
	}
	return result, nil
}

func main() {
	var configPath string
	flag.StringVar(&configPath, "config-path", defaultConfigPath, "DBaaS configuration file path")
	flag.Parse()

	err := config.InitConfig(configPath)
	if err != nil {
		panic(fmt.Sprintf("Initialize configuration failed: %+v", err))
	}

	err = utils.SetupLoggerAndSentry()
	if err != nil {
		panic(fmt.Sprintf("Initialize logger and sentry failed: %+v", err))
	}

	_, err = server.NewServer("Fix blank org names", server.GRPCAuthTypeDumb, grpc_errcode.ErrorFormatDefault)
	if err != nil {
		panic(fmt.Sprintf("Failed to create server: %+v", err))
	}

	ctx := context.Background()

	err = database.Transaction(func(tx *gorm.DB) error {
		orgs, err := ListOrgsWithBlankNames(ctx, tx)
		if err != nil {
			tilog.Info(ctx, "Failed to list orgs")
			return err
		}

		for _, org := range orgs {
			tilog.Info(ctx, "Begin to rename org", zap.Uint64("org_id", org.ID.Uint64()))
			orgName, err := GetNewOrgName(ctx, tx, org)
			if err != nil {
				tilog.Info(ctx, "Failed to get org name", zap.Uint64("org_id", org.ID.Uint64()), zap.Error(err))
				return err
			}
			tilog.Info(ctx, "Renaming org", zap.Uint64("org_id", org.ID.Uint64()), zap.String("org_name", orgName))
			err = RenameOrg(ctx, tx, org, orgName)
			if err != nil {
				tilog.Info(ctx, "Failed to rename org", zap.Uint64("org_id", org.ID.Uint64()), zap.Error(err))
				return err
			}
		}
		return nil
	})
	if err != nil {
		panic(err)
	}
}
