// Package tidbtools implements HTTP handlers for the OPS Portal
// "TiDB Tools" page (DM, changefeeds, imports, backups, restores). Routes are
// registered under `/api/v1/devops/{cluster_id}/tidbtools/*`.
package tidbtools

import (
	"context"

	tidbapi "github.com/tidbcloud/devops/api/tidbtools"
	ctrl "github.com/tidbcloud/devops/pkg/controller"
	configcentercli "github.com/tidbcloud/devops/pkg/infra/clients/configcentercli"
	coresvccli "github.com/tidbcloud/devops/pkg/infra/clients/coresvccli"
	"github.com/tidbcloud/devops/pkg/infra/config"
	cloudconfigapi "github.com/tidbcloud/devops/pkg/service/cloudconfig/api"
	toolsapi "github.com/tidbcloud/devops/pkg/service/tidbtools/api"
	mgmtv1 "github.com/tidbcloud/tidb-management-service/api/spec/tidb_mgmt_service/v1"

	"go.uber.org/dig"
)

// ControllerParam is the dig.In for NewTidbToolsController.
type ControllerParam struct {
	dig.In

	Conf               *config.RootConfig
	TidbToolsService   toolsapi.TidbToolsServiceAPI
	CloudConfigService cloudconfigapi.CloudConfigServiceAPI
	CoreSvcCli         *coresvccli.CoreSvcCli
	// ConfigCenterCli is optional; when nil GetDMOverview returns an empty version.
	ConfigCenterCli *configcentercli.Client `optional:"true"`
}

// TidbToolsController serves all Tools-page endpoints.
type TidbToolsController struct {
	Conf         *config.RootConfig
	svc          toolsapi.TidbToolsServiceAPI
	cloudConfig  cloudconfigapi.CloudConfigServiceAPI
	coreSvcCli   *coresvccli.CoreSvcCli
	cfgCenterCli *configcentercli.Client
}

// Name identifies the controller in the controller registry.
func (c *TidbToolsController) Name() string { return "TidbToolsController" }

// NewTidbToolsController is the dig constructor.
func NewTidbToolsController(p ControllerParam) ctrl.Controller {
	return &TidbToolsController{
		Conf:         p.Conf,
		svc:          p.TidbToolsService,
		cloudConfig:  p.CloudConfigService,
		coreSvcCli:   p.CoreSvcCli,
		cfgCenterCli: p.ConfigCenterCli,
	}
}

// clusterInfo holds access metadata resolved from a single GetCluster RPC.
type clusterInfo struct {
	orgID       uint64
	projectID   uint64
	clusterType tidbapi.ClusterType
	servicePlan string
}

// resolveClusterInfo returns org, project, and cluster type for the given
// cluster ID. It first checks the static override map (used in the live test
// server), then falls back to a coreSvcCli.Mgmt.GetCluster lookup.
func (c *TidbToolsController) resolveClusterInfo(ctx context.Context, clusterID uint64) (clusterInfo, error) {
	cluster, err := c.coreSvcCli.Mgmt.GetCluster(ctx, clusterID)
	if err != nil {
		return clusterInfo{}, err
	}
	ct := logicalType
	if cluster.GetDeployType() == mgmtv1.DeployType_DEPLOY_TYPE_DEDICATED {
		ct = dedicatedType
	}
	servicePlan := cluster.GetServicePlan().String()
	if ct == logicalType && cluster.GetNextGenCluster() != nil {
		servicePlan = cluster.GetNextGenCluster().GetServicePlan().String()
	}
	return clusterInfo{
		orgID:       cluster.GetOrganizationId(),
		projectID:   cluster.GetProjectId(),
		clusterType: ct,
		servicePlan: servicePlan,
	}, nil
}

// RegisterAPI wires the routes under `/:cluster_id/tidbtools`.
func (c *TidbToolsController) RegisterAPI(suite *ctrl.Suite) error {
	r := suite.Router
	cg := r.Group("/:cluster_id/tidbtools")
	{
		// R-0 — aggregated overview
		cg.GET("/overview", c.GetOverview)

		// R-1..R-4 — DM
		cg.GET("/dm/overview", c.GetDMOverview)
		cg.GET("/dm/jobs", c.ListDMJobs)
		cg.GET("/dm/jobs/:job_id", c.GetDMJob)
		cg.GET("/dm/prechecks", c.ListDMPrechecks)
		cg.GET("/dm/prechecks/:precheck_id", c.GetDMPrecheck)

		// R-CF — Changefeeds (CloudConfigService.ListInternalChangefeeds)
		cg.GET("/changefeeds", c.ListChangefeeds)

		// Restores (Dedicated and Next-Gen)
		cg.GET("/restores", c.ListRestores)
		cg.GET("/restores/progress", c.GetRestoreProgress)
		cg.GET("/restores/:restore_id", c.GetRestore)

		// Dedicated
		cg.GET("/backups", c.ListBackups)
		cg.GET("/log-backups", c.ListLogBackups)
		cg.GET("/backup-setting", c.GetBackupSetting)
		cg.GET("/backup-exports", c.ListBackupExports)

		// Imports
		cg.GET("/imports", c.ListImports)

		// Next-Gen
		cg.GET("/nextgen-backup-setting", c.GetNextGenBackupSetting)
		cg.GET("/exports", c.ListExports)
		cg.GET("/import-into-tasks", c.ListImportIntoTasks)
		cg.GET("/import-into-tasks/:task_id", c.GetImportIntoTask)

	}
	return nil
}
