package bss

import (
	"fmt"

	"github.com/stretchr/testify/assert"
	"github.com/tidbcloud/qa-PlatformAPIAuto/common"
	"github.com/tidbcloud/qa-gourd/ProductService"
	"github.com/tidbcloud/qa-gourd/handler"
	"github.com/tidbcloud/qa-gourd/util"
)

func InitBillingTest(w *ProductService.WebRequestInfo, UrlInfoMap map[string]ProductService.UrlInfo, reporter *util.AllureReporter) *BillingTest {
	bt := &BillingTest{}
	bt.Init(w, UrlInfoMap, reporter)

	return bt
}

type BillingTest struct {
	OrgTenantPlan     string
	OrgCredits        *common.Credits
	OrgCreditsSummary *common.CreditsSummary
	OrgPayments       *common.PaymentMethod
	w                 *ProductService.WebRequestInfo
	URLInfoMap        map[string]ProductService.UrlInfo
	Reporter          *util.AllureReporter
	btUserEmail       string
	btOrg             string
	btProject         string
}

func (bt *BillingTest) Init(w *ProductService.WebRequestInfo, UrlInfoMap map[string]ProductService.UrlInfo, reporter *util.AllureReporter) {
	bt.w = w
	bt.URLInfoMap = UrlInfoMap
	bt.Reporter = reporter
}

func (bt *BillingTest) SetbtTestUserEnv(email, orgId, projectId string) {
	bt.btUserEmail = email
	bt.btOrg = orgId
	bt.btProject = projectId
}

func (bt *BillingTest) GetTenantPlan() (*common.TenantPlanInfo, error) {
	pathParam := map[string]string{
		"org_id": bt.w.User.OrgId,
	}
	GetTenantPlanResp := bt.w.DoWebAPIRequestByUrlInfo(bt.URLInfoMap["getTenantPlan"], nil, pathParam, nil)

	tenantPlan, err := util.UnmarshalResult(GetTenantPlanResp, common.TenantPlanInfo{})
	return &tenantPlan, err
}
func (bt *BillingTest) GetFilterTypes() (*common.UnitFilterNode, error) {
	bt.w.ResetRequestEmail(handler.OtherUserInfo.OpsAdminEmail)
	GetCreditsTypesResp := bt.w.DoWebAPIRequestByUrlInfo(bt.URLInfoMap["getFilterTypes"], nil, nil, nil)
	bt.w.ResetRequestEmail(bt.btUserEmail)
	CreditTypes, err := util.UnmarshalResult(GetCreditsTypesResp, common.UnitFilterNode{})
	return &CreditTypes, err
}

// get user's credits list
func (bt *BillingTest) GetCreditsList() (*common.Credits, error) {
	pathParam := map[string]string{
		"org_id": bt.w.User.OrgId,
	}
	GetCreditsListResp := bt.w.DoWebAPIRequestByUrlInfo(bt.URLInfoMap["credits"], nil, pathParam, nil)

	creditsList, err := util.UnmarshalResult(GetCreditsListResp, common.Credits{})
	return &creditsList, err
}

// get user's credits summary
func (bt *BillingTest) GetCreditsSummary() (*common.CreditsSummary, error) {
	pathParam := map[string]string{
		"org_id": bt.w.User.OrgId,
	}
	GetCreditsSummaryResp := bt.w.DoWebAPIRequestByUrlInfo(bt.URLInfoMap["creditsSummary"], nil, pathParam, nil)

	creditsSummary, err := util.UnmarshalResult(GetCreditsSummaryResp, common.CreditsSummary{})
	return &creditsSummary, err
}

func (bt *BillingTest) GetPaymentMethod() (*common.PaymentMethod, error) {
	pathParam := map[string]string{
		"org_id": bt.w.User.OrgId,
	}
	GetPaymentMethodResp := bt.w.DoWebAPIRequestByUrlInfo(bt.URLInfoMap["getTenantPayment"], nil, pathParam, nil)

	paymentMethod, err := util.UnmarshalResult(GetPaymentMethodResp, common.PaymentMethod{})
	return &paymentMethod, err
}
func (bt *BillingTest) SetOrgTenantPlan() *common.TenantPlanInfo {
	tenantPlan, err := bt.GetTenantPlan()
	if err != nil {
		assert.Fail(bt.Reporter.T, fmt.Sprintf("GetTenantPlan failed, err is %s", err))
	}
	bt.OrgTenantPlan = tenantPlan.EffectivePlan

	return tenantPlan
}

func (bt *BillingTest) SetOrgTenantCredits() *common.Credits {
	creditsList, err := bt.GetCreditsList()
	if err != nil {
		assert.Fail(bt.Reporter.T, fmt.Sprintf("GetCreditsList failed, err is %s", err))
	}
	bt.OrgCredits = creditsList

	return creditsList
}

func (bt *BillingTest) SetOrgTenantCreditsSummary() *common.CreditsSummary {
	creditsSummary, err := bt.GetCreditsSummary()
	if err != nil {
		assert.Fail(bt.Reporter.T, fmt.Sprintf("GetCreditsSummary failed, err is %s", err))
	}
	bt.OrgCreditsSummary = creditsSummary

	return creditsSummary
}
func (bt *BillingTest) SetOrgTenantPayment() *common.PaymentMethod {
	payment, err := bt.GetPaymentMethod()
	if err != nil {
		assert.Fail(bt.Reporter.T, fmt.Sprintf("GetPaymentMethod failed, err is %s", err))
	}
	bt.OrgPayments = payment

	return payment
}

func (bt *BillingTest) SearchFilterTypeId(targetType []string) map[string]uint {
	filterType, err := bt.GetFilterTypes()
	if err != nil {
		assert.Fail(bt.Reporter.T, fmt.Sprintf("GetCreditsTypes failed, err is %s", err))
	}
	// recursion func to find credits type id by type name
	var getIdByNamePreorder func(*common.UnitFilterNode, string) *common.UnitFilterNode
	getIdByNamePreorder = func(children *common.UnitFilterNode, name string) *common.UnitFilterNode {
		if children == nil || children.Name == name {
			return children
		}
		for _, child := range children.Children {
			if res := getIdByNamePreorder(child, name); res != nil {
				return res
			}
		}
		return nil
	}

	res := make(map[string]uint)
	for _, target := range targetType {
		if id := getIdByNamePreorder(filterType, target); id != nil {
			res[target] = id.FilterID
		}
	}
	return res
}

type BillsCheck struct {
	Amount       string
	BillableCost string
	CreditUsage  string
	DiscountCost string
	ClusterName  string
	ProjectName  string
	Service      string
	BilledDate   string
}

type ExpectBillsResult struct {
	CheckItems []BillsCheck
}
