package deps

import (
	"crypto/tls"

	userv1 "github.com/tidbcloud/aisupport/packages/sdk-go/contracts/api/core-server/user/v1"
	"github.com/tidbcloud/devops/pkg/infra/clients/accountcli"
	"github.com/tidbcloud/devops/pkg/infra/clients/aiopscli"
	"github.com/tidbcloud/devops/pkg/infra/clients/billingcli"
	"github.com/tidbcloud/devops/pkg/infra/clients/cliniccli"
	"github.com/tidbcloud/devops/pkg/infra/clients/configcentercli"
	"github.com/tidbcloud/devops/pkg/infra/clients/coresvccli"
	"github.com/tidbcloud/devops/pkg/infra/clients/dataflowcli"
	"github.com/tidbcloud/devops/pkg/infra/clients/githubcli"
	"github.com/tidbcloud/devops/pkg/infra/clients/metadbcli"
	"github.com/tidbcloud/devops/pkg/infra/clients/mgmthttpcli"
	"github.com/tidbcloud/devops/pkg/infra/clients/o11ycli"
	"github.com/tidbcloud/devops/pkg/infra/clients/oncallcli"
	"github.com/tidbcloud/devops/pkg/infra/clients/opscore"
	"github.com/tidbcloud/devops/pkg/infra/clients/serverlesscli"
	"github.com/tidbcloud/devops/pkg/infra/config"
	"github.com/tidbcloud/devops/pkg/infra/secretsource"
	gormutil "github.com/tidbcloud/devops/pkg/infra/utils/gorm"

	"github.com/go-logr/logr"
	"github.com/go-sql-driver/mysql"
	"github.com/robfig/cron/v3"
	"github.com/tidbcloud/pkgv2/db"
	"gorm.io/gorm"
)

func newGormDB(rootConf *config.RootConfig) (*gorm.DB, error) {
	handle, err := gormutil.Connect(rootConf.MySQL, "DevOpsDB")
	if err != nil {
		return nil, err
	}
	return handle, nil
}

func newDBProvider(handle *gorm.DB) db.TransProvider {
	return db.NewProvider(handle)
}

func newCron(conf *config.RootConfig) *cron.Cron {
	return cron.New()
}

func newSecretSource(conf *config.RootConfig) (secretsource.SecretSource, error) {
	return secretsource.NewSecretSource(conf.SecretSource)
}

func newCoreSvcCli(conf *config.RootConfig) (*coresvccli.CoreSvcCli, error) {
	return coresvccli.NewCoreSvcCli(conf.DbaasAddr.CoreServiceAddr, conf.DbaasAddr.MgmtServiceAddr, conf.DbaasAddr.NextGenGlobalAddr)
}

func newOpsCoreClient(conf *config.RootConfig) (*opscore.Client, error) {
	return opscore.NewClient(conf.DbaasAddr.OpsCoreServiceAddr)
}

func newOpsCoreUserClient(client *opscore.Client) userv1.UserServiceClient {
	return client.User
}

func newGithubActionClient(conf *config.RootConfig) (githubcli.Client, error) {
	return githubcli.NewClient(conf.Clients.GithubAction.Owner, conf.Clients.GithubAction.Repo, conf.Clients.Github.Token)
}

func newAccountSvcCli(conf *config.RootConfig, logger logr.Logger) (accountcli.Client, error) {
	addr := conf.DbaasAddr.AccountServiceAddr
	httpAddr := conf.DbaasAddr.AccountHttpAddr
	ak := conf.Clients.AccountServer.AK
	sk := conf.Clients.AccountServer.SK

	return accountcli.NewClient(addr, httpAddr, ak, sk, logger)
}

func newBillingSvcCli(conf *config.RootConfig, logger logr.Logger) (billingcli.Client, error) {
	addr := conf.DbaasAddr.BillingServiceAddr

	return billingcli.NewClient(addr)
}

func newMgmtHTTPCli(conf *config.RootConfig, coreSvcCli *coresvccli.CoreSvcCli) (mgmthttpcli.MgmtHTTPClient, error) {
	addr := conf.DbaasAddr.MgmtService.HTTPAddr
	token := conf.DbaasAddr.MgmtService.HTTPToken

	return mgmthttpcli.NewMgmtHTTPClient(addr, token, coreSvcCli)
}

func newServerlessSvcCli(conf *config.RootConfig, logger logr.Logger) (*serverlesscli.Client, error) {
	addr := conf.DbaasAddr.ServerlessServiceAddr

	return serverlesscli.NewClient(addr, logger)
}

func newConfigCenterCli(conf *config.RootConfig) (*configcentercli.Client, error) {
	return configcentercli.NewClient(conf.DbaasAddr.ConfigCenterAddr)
}

func newDataflowCli(conf *config.RootConfig) (*dataflowcli.DataflowCli, error) {
	return dataflowcli.NewDataflowCli(conf.DbaasAddr.DataflowServiceAddr, conf.DbaasAddr.DataflowNgServiceAddr)
}

func newClinicCli(conf *config.RootConfig) (cliniccli.Client, error) {
	return cliniccli.NewClient(conf.Clients.ClinicServer.Addr, conf.Clients.ClinicServer.Token)
}

func newAIOpsServerCli(conf *config.RootConfig) (aiopscli.Client, error) {
	return aiopscli.NewClient(conf.Clients.AIOpsServer.Addr, conf.Clients.AIOpsServer.APIKey)
}

func newO11yCli(conf *config.RootConfig) (o11ycli.Client, error) {
	addr := conf.DbaasAddr.O11yServiceAddr

	return o11ycli.NewClient(addr)
}

func newOnCallCli(conf *config.RootConfig) (oncallcli.Client, error) {
	if conf.Clients.OnCall.Dummy {
		return nil, nil
	}
	return oncallcli.NewClient(conf.Clients.OnCall.Addr, conf.Clients.OnCall.ServiceKey)
}

func newMetaDBClient(conf *config.RootConfig) (metadbcli.Client, error) {
	if err := mysql.RegisterTLSConfig("tidb", &tls.Config{
		MinVersion: tls.VersionTLS12,
		ServerName: conf.DbaasAddr.CloudInfraMetaDB.Host,
	}); err != nil {
		return nil, err
	}
	conf.DbaasAddr.CloudInfraMetaDB.TLSConfigKey = "tidb"
	return metadbcli.NewClient(gormutil.GenerateDSN(conf.DbaasAddr.CloudInfraMetaDB))
}
