package main

import (
	"context"
	"fmt"
	"grpc-test/pkg/db"
	"sync"
	"time"

	entity "github.com/tidbcloud/core-svc/model"
	"github.com/tidbcloud/pkgv2/log"
	tigrpc "github.com/tidbcloud/tiinf/transport/tigrpc/client"
	"go.uber.org/zap"
	"google.golang.org/protobuf/types/known/timestamppb"

	"github.com/tidbcloud/account/idl/pbgen/proto/account"
	"github.com/tidbcloud/pkgv2/bizerr"
)

func main() {
	ctx := context.Background()
	req := &account.OrgFilter{Ids: []uint64{}}
	orgsResp, err := ListOrgs(ctx, req)
	if err != nil {
		fmt.Println(err)
		return
	}
	orgs := orgsResp.Orgs
	tenants := make([]db.Tenant, 0)
	for _, org := range orgs {
		if org.Plan == "poc" || org.Plan == "on_demand" {
			tenants = append(tenants, db.Tenant{Id: org.Id, Name: org.Name, Alias: org.Alias, Plan: org.Plan})
		}
	}
	err0 := db.InsertTenant(tenants)
	if err0 != nil {
		fmt.Println(err)
		return
	}
}

var (
	accountProviderSvcOnce sync.Once
	accountProviderSvcCli  account.AccountAPIServiceClient
)

func getAccountProviderSvcClient() account.AccountAPIServiceClient {
	accountProviderSvcOnce.Do(func() {
		conn, err := tigrpc.NewClientConn("account-provider-grpc:10000", tigrpc.WithDefault())
		if err != nil {
			panic(fmt.Sprintf("dial account-provider-svc: %s", err))
		}

		accountProviderSvcCli = account.NewAccountAPIServiceClient(conn)
	})

	return accountProviderSvcCli
}

func GetAuthUser(ctx context.Context, req *account.GetAuthUserRequest) (*account.GetAuthUserResponse, bizerr.BizError) {
	client := getAccountProviderSvcClient()

	resp, e := client.GetAuthUser(ctx, req)
	if e != nil {
		return resp, bizerr.WrapGrpcError(e, "GetAuthUser")
	}
	if resp.BaseResp.ErrCode != 0 {
		return resp, bizerr.Restore(bizerr.ErrCode(resp.BaseResp.ErrCode), resp.BaseResp.ErrMsg)
	}
	return resp, nil
}

func GetOrCreateSystemUser(ctx context.Context, req *account.GetOrCreateSystemUserRequest) (*account.GetOrCreateSystemUserResponse, bizerr.BizError) {
	client := getAccountProviderSvcClient()

	resp, e := client.GetOrCreateSystemUser(ctx, req)
	if e != nil {
		return resp, bizerr.WrapGrpcError(e, "GetOrCreateSystemUser")
	}
	if resp.BaseResp.ErrCode != 0 {
		return resp, bizerr.Restore(bizerr.ErrCode(resp.BaseResp.ErrCode), resp.BaseResp.ErrMsg)
	}
	return resp, nil
}

func GetUserByID(ctx context.Context, id uint64) (*account.User, bizerr.BizError) {
	getUserRequest := &account.GetUserByIDRequest{
		UserId: id,
	}
	user, err := _getUserByID(ctx, getUserRequest)
	if err != nil {
		log.Error(ctx, "fail to call account-svc GetUserByID API", zap.String("id", fmt.Sprint(id)), zap.Error(err))
		return nil, err
	}

	return user.User, nil
}

func _getUserByID(ctx context.Context, req *account.GetUserByIDRequest) (*account.GetUserByIDResponse, bizerr.BizError) {
	client := getAccountProviderSvcClient()

	resp, e := client.GetUserByID(ctx, req)
	if e != nil {
		return resp, bizerr.WrapGrpcError(e, "GetUserByID")
	}
	if resp.BaseResp.ErrCode != 0 {
		return resp, bizerr.Restore(bizerr.ErrCode(resp.BaseResp.ErrCode), resp.BaseResp.ErrMsg)
	}
	return resp, nil
}

func ListProjects(ctx context.Context, req *account.ProjectFilter) (*account.ListProjectsResponse, bizerr.BizError) {
	client := getAccountProviderSvcClient()

	resp, e := client.ListProjects(ctx, req)
	if e != nil {
		return resp, bizerr.WrapGrpcError(e, "ListProjects")
	}
	if resp.BaseResp.ErrCode != 0 {
		return resp, bizerr.Restore(bizerr.ErrCode(resp.BaseResp.ErrCode), resp.BaseResp.ErrMsg)
	}
	return resp, nil
}

func GetOrgByID(ctx context.Context, id uint64) (*account.Org, bizerr.BizError) {
	log.Info(ctx, "request to account-svc GetOrgByID API", zap.String("id", fmt.Sprint(id)))
	getOrgByIDRequest := &account.GetOrgByIDRequest{
		Id: id,
	}
	org, err := _getOrgByID(ctx, getOrgByIDRequest)
	if err != nil {
		log.Error(ctx, "fail to call account-svc GetOrgByID API", zap.String("id", fmt.Sprint(id)), zap.Error(err))
		return nil, err
	}
	return org.Org, nil
}

func _getOrgByID(ctx context.Context, req *account.GetOrgByIDRequest) (*account.GetOrgByIDResponse, bizerr.BizError) {
	client := getAccountProviderSvcClient()

	resp, e := client.GetOrgByID(ctx, req)
	if e != nil {
		return resp, bizerr.WrapGrpcError(e, "GetOrgByID")
	}
	if resp.BaseResp.ErrCode != 0 {
		return resp, bizerr.Restore(bizerr.ErrCode(resp.BaseResp.ErrCode), resp.BaseResp.ErrMsg)
	}
	return resp, nil
}

func ListOrgs(ctx context.Context, req *account.OrgFilter) (*account.ListOrgsResponse, bizerr.BizError) {
	client := getAccountProviderSvcClient()

	resp, e := client.ListOrgs(ctx, req)
	if e != nil {
		return resp, bizerr.WrapGrpcError(e, "ListOrgs")
	}
	if resp.BaseResp.ErrCode != 0 {
		return resp, bizerr.Restore(bizerr.ErrCode(resp.BaseResp.ErrCode), resp.BaseResp.ErrMsg)
	}
	return resp, nil
}

func CreateAuditLog(ctx context.Context, tenantID entity.ID, user string, content string) (*account.AuditLog, bizerr.BizError) {
	log.Info(ctx, "request to account-svc CreateAuditLog API")
	createAuditLogRequest := &account.CreateAuditLogRequest{
		AuditLog: &account.AuditLog{
			OrgId:     tenantID.Uint64(),
			User:      user,
			Content:   content,
			CreatedAt: timestamppb.New(time.Unix(time.Now().Unix(), 0)),
		},
	}
	res, err := _createAuditLog(ctx, createAuditLogRequest)
	if err != nil {
		log.Error(ctx, "fail to call account-svc CreateAuditLog API", zap.Error(err))
		return nil, err
	}
	return res.AuditLog, nil
}

func _createAuditLog(ctx context.Context, req *account.CreateAuditLogRequest) (*account.CreateAuditLogResponse, bizerr.BizError) {
	client := getAccountProviderSvcClient()

	resp, e := client.CreateAuditLog(ctx, req)
	if e != nil {
		return resp, bizerr.WrapGrpcError(e, "CreateAuditLog")
	}
	if resp.BaseResp.ErrCode != 0 {
		return resp, bizerr.Restore(bizerr.ErrCode(resp.BaseResp.ErrCode), resp.BaseResp.ErrMsg)
	}
	return resp, nil
}

func GetUserByEmail(ctx context.Context, email string) (*account.User, bizerr.BizError) {
	log.Info(ctx, "request to account-svc GetUserByEmail API", zap.String("email", email))
	getUserByEmailRequest := &account.GetUserByEmailRequest{
		Email: email,
	}
	user, err := _getUserByEmail(ctx, getUserByEmailRequest)
	if err != nil {
		log.Error(ctx, "fail to call account-svc GetUserByEmail API", zap.String("email", email), zap.Error(err))
		return nil, err
	}
	return user.User, nil
}

func _getUserByEmail(ctx context.Context, req *account.GetUserByEmailRequest) (*account.GetUserByEmailResponse, bizerr.BizError) {
	client := getAccountProviderSvcClient()

	resp, e := client.GetUserByEmail(ctx, req)
	if e != nil {
		return resp, bizerr.WrapGrpcError(e, "GetUserByEmail")
	}
	if resp.BaseResp.ErrCode != 0 {
		return resp, bizerr.Restore(bizerr.ErrCode(resp.BaseResp.ErrCode), resp.BaseResp.ErrMsg)
	}
	return resp, nil
}
