package bss

import (
	"fmt"

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

const (
	ContractFilePath     = "1fb0ea11-1203-4b26-aac0-040a0d865b24.pdf"
	OriginalContractType = "saving_plan_order_form"
	EditedContractType   = "poc_agreement"
	EditedContractId     = "QA-auto-scene-edit"
)

type ContractTest struct {
	w          *ProductService.WebRequestInfo
	URLInfoMap map[string]ProductService.UrlInfo
	Reporter   *util.AllureReporter
	cUser      string
}

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

func RunContractTest(w *ProductService.WebRequestInfo, UrlInfoMap map[string]ProductService.UrlInfo, reporter *util.AllureReporter) {
	c := &ContractTest{}
	c.Init(w, UrlInfoMap, reporter)
	c.ContractOperation()
}

// contract operation scene
func (c *ContractTest) ContractOperation() {

	contractId := c.CheckOPSCreateContract()
	c.CheckOPSEditContract(contractId)
	c.CheckOPSSubmitContract(contractId)
	c.CheckOPSContractStatus(contractId, "submit")
	c.CheckDBaaSAcceptContract(contractId)
	c.CheckDBaaSContractStatus(contractId, "active")

}

func (c *ContractTest) CheckOPSCreateContract() string {

	ContractId := common.GenTempName() + "QA-auto-scene"
	createContractBody := common.NewContract(OriginalContractType, ContractId, c.w.User.TenantEmail, ContractFilePath)
	createContractParam := map[string]string{
		"org_id": c.w.User.OrgId,
	}

	c.cUser = c.w.User.TenantEmail
	c.w.ResetRequestEmail(handler.OtherUserInfo.OpsAdminEmail)
	createContractResp := c.w.DoWebAPIRequestByUrlInfo(c.URLInfoMap["createContract"], createContractBody, createContractParam, nil)

	c.Reporter.StepReport(fmt.Sprintf("createContractResp's status is %s (should be draft)",
		createContractResp.JSON().Path("$.status").String().Raw(),
	), func() {
		createContractResp.JSON().Path("$.status").String().IsEqual("draft")
	})

	return fmt.Sprintf("%1.0f", createContractResp.JSON().Path("$.id").Number().Raw())
}

func (c *ContractTest) CheckOPSEditContract(contractId string) {

	editContractBody := common.NewContract(EditedContractType, EditedContractId, c.w.User.TenantEmail, ContractFilePath)
	editContractParam := map[string]string{
		"org_id": c.w.User.OrgId,
		"id":     contractId,
	}

	c.w.ResetRequestEmail(handler.OtherUserInfo.OpsAdminEmail)
	editContractResp := c.w.DoWebAPIRequestByUrlInfo(c.URLInfoMap["editContract"], editContractBody, editContractParam, nil)

	c.Reporter.StepReport(fmt.Sprintf("after editing contract, type is %s (should be %s) , Id is %s (should be %s)",
		editContractResp.JSON().Path("$.contract_type").String().Raw(),
		EditedContractType,
		editContractResp.JSON().Path("$.contract_id").String().Raw(),
		EditedContractId,
	), func() {
		editContractResp.JSON().Path("$.status").String().IsEqual("draft")
	})
}

func (c *ContractTest) CheckOPSSubmitContract(contractId string) {
	// ops submit draft
	submitContractParam := map[string]string{
		"org_id": c.w.User.OrgId,
		"id":     contractId,
	}
	c.w.ResetRequestEmail(handler.OtherUserInfo.OpsAdminEmail)
	submitContractResp := c.w.DoWebAPIRequestByUrlInfo(c.URLInfoMap["submitContract"], nil, submitContractParam, nil)

	c.Reporter.StepReport(fmt.Sprintf("submit contract, status is %s (should be ok)",
		submitContractResp.JSON().Path("$.status").String().Raw(),
	), func() {
		submitContractResp.JSON().Path("$.status").String().IsEqual("ok")
	})
}

func (c *ContractTest) CheckOPSContractStatus(contractId string, expectStatus string) {
	// ops check contract status
	getContractParam := map[string]string{
		"org_id": c.w.User.OrgId,
		"id":     contractId,
	}
	c.w.ResetRequestEmail(handler.OtherUserInfo.OpsAdminEmail)
	getAdminContractResp := c.w.DoWebAPIRequestByUrlInfo(c.URLInfoMap["getAdminContract"], nil, getContractParam, nil)

	c.Reporter.StepReport(fmt.Sprintf("check contract's status is %s (should be %s)",
		getAdminContractResp.JSON().Path("$.status").String().Raw(),
		expectStatus,
	), func() {
		getAdminContractResp.JSON().Path("$.status").String().IsEqual(expectStatus)
	})
}

func (c *ContractTest) CheckDBaaSAcceptContract(contractId string) {
	// dbaas accept draft
	acceptContractParam := map[string]string{
		"org_id": c.w.User.OrgId,
		"id":     contractId,
	}
	c.w.ResetRequestEmail(c.cUser)
	acceptContractResp := c.w.DoWebAPIRequestByUrlInfo(c.URLInfoMap["acceptContract"], nil, acceptContractParam, nil)

	c.Reporter.StepReport(fmt.Sprintf("dbaas accept contract's status is %s (should be ok)",
		acceptContractResp.JSON().Path("$.status").String().Raw(),
	), func() {
		acceptContractResp.JSON().Path("$.status").String().IsEqual("ok")
	})
}

func (c *ContractTest) CheckDBaaSContractStatus(contractId string, expectStatus string) {
	// dbaas check contract status
	getContractParam := map[string]string{
		"org_id": c.w.User.OrgId,
		"id":     contractId,
	}
	c.w.ResetRequestEmail(c.cUser)
	getContractResp := c.w.DoWebAPIRequestByUrlInfo(c.URLInfoMap["getContract"], nil, getContractParam, nil)

	c.Reporter.StepReport(fmt.Sprintf("dbaas check contract's status is %s (should be %s), last operator id is %v (should not be null)",
		getContractResp.JSON().Path("$.status").String().Raw(),
		expectStatus,
		getContractResp.JSON().Path("$.last_operator_id").Number().Raw(),
	), func() {
		getContractResp.JSON().Path("$.status").String().IsEqual(expectStatus)
		getContractResp.JSON().Path("$.last_operator_id").NotNull()
	})
}
