package cloud

import (
	"context"
	"time"

	"github.com/pingcap/errors"
	"github.com/pingcap/log"
	"github.com/tidbcloud/account/idl/pbgen/proto/account"
	"go.uber.org/zap"

	"github.com/pingcap-inc/clinic/pkg/auth/session"
	"github.com/pingcap-inc/clinic/pkg/datasource/internal/cloud/internal"
	"github.com/pingcap-inc/clinic/pkg/datasource/view"
	"github.com/pingcap-inc/clinic/pkg/db"
	"github.com/pingcap-inc/clinic/pkg/db/model"
)

func ListOrganizations(ctx *session.CtxUser, filter view.QueryFilter) (any, int64, error) {
	// if !isInternal(ctx) {
	// 	return nil, 0, errors.New("permission deny")
	// }

	cond, ok := filter.ExtraFilter.(*model.ListOrganizationsCondition)
	if !ok {
		return nil, 0, errors.New("unsupport extra filter type")
	}
	cond.Page = filter.Page
	cond.PerPage = filter.Limit

	return internal.ListOrganizations(cond)
}

func LastUpdatedTime(ctx *session.CtxUser, org *db.Organization, projectIDs []uint64, excludeServerless bool) (int, int64, error) {
	c, _, err := internal.CountActiveClustersByOrgID(uint64(org.DbaasOrgID), projectIDs, excludeServerless)
	if err != nil {
		return c, 0, err
	}
	return c, org.UpdatedAt.Unix(), nil
}

func ListRealTimeOrganizations(ctx *session.CtxUser) ([]*account.Org, int64, error) {
	if !isInternal(ctx) {
		return nil, 0, errors.New("permission deny")
	}

	return listCloudOrganizations(&model.ListOrganizationsCondition{})
}

func RealtimeGetOrganization(uctx *session.CtxUser, tenantID uint64) (*account.Org, error) {
	if !isInternal(uctx) {
		return nil, errors.New("permission deny")
	}

	ctx, cancel := context.WithTimeout(context.Background(), 40*time.Second)
	defer cancel()
	resp, err := accountC.GetOrgByID(ctx, &account.GetOrgByIDRequest{Id: tenantID})
	if err != nil {
		return nil, errors.Annotate(err, "call grpc failed")
	}
	// https://github.com/tidbcloud/pkgv2/blob/main/bizerr/code.go#L35
	if resp.GetBaseResp().GetErrCode() != 0 {
		log.Error("biz code not zero", zap.Int64("err_code", resp.GetBaseResp().GetErrCode()), zap.String("err_msg", resp.GetBaseResp().GetErrMsg()))
		return nil, errors.New(resp.GetBaseResp().String())
	}

	return resp.GetOrg(), nil
}

func GetOrganization(ctx *session.CtxUser, orgID uint) (*db.Organization, error) {
	// if !isInternal(ctx) {
	// 	return nil, errors.New("permission deny")
	// }

	return internal.GetOrganization(orgID)
}

func GetOrganizationByExternalID(ctx *session.CtxUser, externalID uint) (*db.Organization, error) {
	if !isInternal(ctx) {
		return nil, errors.New("permission deny")
	}

	return internal.GetOrgByExternalID(externalID, view.CloudDataSource)
}

type OrganizationItem struct {
	ID        string `json:"id"`
	Name      string `json:"name"`
	Email     string `json:"email"`
	Status    string `json:"status"`
	CreatedAt int64  `json:"created_at"`
	UpdatedAt int64  `json:"updated_at"`
}

func listCloudOrganizations(_ *model.ListOrganizationsCondition) ([]*account.Org, int64, error) {
	var (
		orgs []db.Organization
		err  error
	)

	ctx, cancel := context.WithTimeout(context.Background(), 40*time.Second)
	defer cancel()
	resp, err := accountC.ListOrgs(ctx, &account.OrgFilter{})
	if err != nil {
		return nil, 0, errors.Annotate(err, "call grpc failed")
	}
	// https://github.com/tidbcloud/pkgv2/blob/main/bizerr/code.go#L35
	if resp.GetBaseResp().GetErrCode() != 0 {
		log.Error("biz code not zero", zap.Int64("err_code", resp.GetBaseResp().GetErrCode()), zap.String("err_msg", resp.GetBaseResp().GetErrMsg()))
		return nil, 0, errors.New(resp.GetBaseResp().String())
	}
	log.Info("get orgs", zap.Int("num", len(resp.GetOrgs())))

	return resp.GetOrgs(), int64(len(orgs)), nil
}
