package admin

import (
	"strings"

	"github.com/pingcap/errors"
	"github.com/tidbcloud/central-sdk/db"
	"github.com/tidbcloud/central-sdk/db/dbutil"
	"github.com/tidbcloud/central-sdk/db/entity"
	centralModel "github.com/tidbcloud/central-sdk/model"
	"go.uber.org/zap"
	"gorm.io/gorm"
)

type TenantBillingStatus struct {
	RemainingCredit int64
	TotalCredit     int64
	NodeUsageFee    int64
}

func (m UserContext) GetTenantBillingStatus(tenantID uint64) (*TenantBillingStatus, error) {
	if m.tenantAndUser.ID == 0 {
		return nil, errors.New("not a normal user")
	}

	var (
		totalAmount int64
		trialUsage  int64
		err         error
	)
	err = db.Transaction(func(tx *gorm.DB) error {
		totalAmount, err = dbutil.GetTotalFreeTrialPoint(tx, entity.ID(tenantID))
		if err != nil {
			return err
		}
		trialUsage, err = centralModel.GetNodeUsageFromDB(tx, entity.ID(tenantID))
		return err
	})
	if err != nil {
		m.log.Error("failed to call GetTotalFreeTrialPoint", zap.Uint64("TenantID", tenantID))
		return nil, err
	}
	return &TenantBillingStatus{
		RemainingCredit: totalAmount - trialUsage,
		TotalCredit:     totalAmount,
		NodeUsageFee:    trialUsage,
	}, nil
}

func (m UserContext) ForwardBillingRequest(method, path, payload string) (string, error) {
	if m.tenantAndUser.ID == 0 {
		return "", errors.New("not a normal user")
	}
	method = strings.ToUpper(method)
	var data []byte
	if method != "GET" && payload != "" {
		data = []byte(payload)
	}
	return m.billingClient.GetHttpResultAsString(method, path, data)
}

type NodeUsage struct {
	ID        uint64
	StartTime int64
	EndTime   int64
	Usage     int64
}

func (m UserContext) GetNodeUsage(tenantID uint64) (*NodeUsage, error) {
	var usage entity.NodeUsage
	err := db.Transaction(func(tx *gorm.DB) error {
		return entity.NewNodeUsageQuerySet(tx).TenantIDEq(entity.ID(tenantID)).One(&usage)
	})
	if err != nil {
		return nil, err
	}
	return &NodeUsage{
		ID:        usage.ID.Uint64(),
		StartTime: usage.StartTime,
		EndTime:   usage.EndTime,
		Usage:     usage.Usage,
	}, err
}

func (m UserContext) UpdateNodeUsage(tenantID uint64, startTime, endTime, newValue int64) error {
	var usage entity.NodeUsage
	return db.Transaction(func(tx *gorm.DB) error {
		if err := entity.NewNodeUsageQuerySet(tx).TenantIDEq(entity.ID(tenantID)).One(&usage); err != nil {
			return err
		}
		usage.StartTime = startTime
		usage.EndTime = endTime
		usage.Usage = newValue
		return usage.Update(tx, entity.NodeUsageDBSchema.StartTime, entity.NodeUsageDBSchema.EndTime, entity.NodeUsageDBSchema.Usage)
	})
}
