package debugportal

import (
	"context"
	"fmt"
	"time"

	"github.com/gogo/protobuf/types"
	"github.com/pingcap/dbaas/central/grpc/grpcli"
	"github.com/pingcap/dbaas/central/model/admin"
	"github.com/pingcap/errcode"
	"github.com/pingcap/errors"
	"github.com/tidbcloud/idl/pbgen/proto/base"
	"github.com/tidbcloud/idl/pbgen/proto/central"
	"github.com/tidbcloud/idl/pbgen/proto/core"
	"k8s.io/utils/pointer"
)

func (service *debugPortalService) ListTenants(context context.Context, req *central.ListTenantsReq) (*central.ListTenantsResp, error) {
	if err := service.authN(context); err != nil {
		return nil, err
	}
	// FIXME: Currently this is completely copied from admin model.
	items, total, err := service.model.ListTenants(req.Name, req.Id, req.Page, req.PerPage)
	if err != nil {
		return nil, err
	}
	var results = &central.ListTenantsResp{
		Total: uint32(total),
		Items: []*central.Tenant{},
	}
	for _, item := range items {
		t := buildAPITenantItem(item)
		results.Items = append(results.Items, t)
	}
	return results, nil
}

func buildAPITenantItem(item *admin.Tenant) *central.Tenant {
	// FIXME: Currently this is completely copied from admin model.
	t := &central.Tenant{
		Id:                  item.ID.Uint64(),
		Name:                item.Name,
		Email:               item.Email,
		Timezone:            item.Timezone,
		Status:              item.Status,
		Plan:                item.Plan,
		DiscountDescription: item.DiscountDescription,
		Discount:            item.Discount,
		Country:             item.Country,
		HasDiscount:         item.HasDiscount,
	}
	return t
}

func (service *debugPortalService) GetTenantById(context context.Context, req *central.OrgIdReq) (*central.Tenant, error) {
	if err := service.authN(context); err != nil {
		return nil, err
	}
	// FIXME: Currently this is completely copied from admin model.
	items, _, err := service.model.ListTenants("", req.OrgId, 0, 0)
	if err != nil {
		return nil, err
	}
	if len(items) > 0 {
		return buildAPITenantItem(items[0]), nil
	}
	return nil, errcode.NewNotFoundErr(fmt.Errorf("organization <%d> is not found", req.OrgId))
}

func (service *debugPortalService) ListTenantClusters(ctx context.Context, req *central.ListTenantClustersReq) (*central.ListTenantClustersResp, error) {
	if err := service.authN(ctx); err != nil {
		return nil, err
	}
	filter := &core.ClusterFilter{
		TenantIds: []uint64{req.OrgId},
		Deleted:   pointer.BoolPtr(false),
	}
	pager := &base.Pager{
		Page:     int64(req.Page),
		PageSize: int64(req.PerPage),
	}
	sorter := &base.Sorter{
		OrderBy: "created_at",
		Sort:    base.Sort_SORT_DESC,
	}

	listReq := &core.ListClustersReq{
		Filter:  filter,
		Pager:   pager,
		Sorter:  sorter,
		BaseReq: nil,
	}
	listResp, err := grpcli.ListClusters(ctx, listReq)
	if err != nil {
		return nil, err
	}
	countResp, err := grpcli.CountClusters(ctx, &core.CountClustersReq{Filter: filter})
	if err != nil {
		return nil, err
	}

	outs := make([]*central.TenantCluster, 0, len(listResp.Clusters))
	for _, clusterId := range listResp.OrderedClusterIds {
		cluster := listResp.Clusters[clusterId]
		createdAt, _ := types.TimestampProto(time.Unix(cluster.CreatedAt, 0))

		out := &central.TenantCluster{
			Id:                       int64(cluster.Id),
			Name:                     cluster.Name,
			Provider:                 cluster.CloudProviderName,
			Region:                   cluster.RegionName,
			Profile:                  "", // not used
			Version:                  cluster.Version,
			CreateTime:               createdAt,
			TenantComponents:         &central.TenantComponents{},
			Status:                   central.Cluster_Status(cluster.UserStatus),
			CrossAccountDeploymentId: cluster.XaccountDeployId,
		}
		for _, component := range cluster.Components {
			switch component.ComponentType {
			case core.ComponentType_COMPONENT_TYPE_TIDB:
				out.TenantComponents.Tidb = &central.TenantComponent{
					Replicas:    uint32(component.Replicas),
					MachineType: component.ComputeInstanceType,
				}
			case core.ComponentType_COMPONENT_TYPE_PD:
				out.TenantComponents.Pd = &central.TenantComponent{
					Replicas:    uint32(component.Replicas),
					MachineType: component.ComputeInstanceType,
				}
			case core.ComponentType_COMPONENT_TYPE_TIFLASH:
				out.TenantComponents.Tiflash = &central.TenantComponent{
					Replicas:    uint32(component.Replicas),
					MachineType: component.ComputeInstanceType,
				}
			case core.ComponentType_COMPONENT_TYPE_TIKV:
				out.TenantComponents.Tikv = &central.TenantComponent{
					Replicas:    uint32(component.Replicas),
					MachineType: component.ComputeInstanceType,
				}
			default:
				return nil, errors.Errorf("unknown component %s", string(component.ComponentType))
			}
		}
		outs = append(outs, out)
	}
	return &central.ListTenantClustersResp{
		Total: uint32(countResp.Count),
		Items: outs,
	}, nil
}

func (service *debugPortalService) GetDashboardLinks(context context.Context, req *central.GetDashboardLinksReq) (*central.GetDashboardLinksResp, error) {
	if err := service.authN(context); err != nil {
		return nil, err
	}
	// FIXME: Currently this is completely copied from admin model.
	ds, err := service.model.GetDashboardLinks(req.OrgId, req.ClusterId)
	if err != nil {
		return nil, err
	}
	var items []*central.DashboardLink
	for _, item := range ds {
		items = append(items, &central.DashboardLink{Name: item.Name, Link: item.Link})
	}
	return &central.GetDashboardLinksResp{Dashboards: items}, nil
}
