package tests

import (
	"testing"

	"github.com/google/uuid"
	"github.com/pingcap/dbaas/billing2/config"
	"github.com/pingcap/dbaas/billing2/db"
	"github.com/pingcap/dbaas/billing2/db/entity"
	"github.com/pingcap/dbaas/billing2/forms"
	"github.com/pingcap/dbaas/billing2/model/payment/paymentsub"
	"github.com/pingcap/dbaas/billing2/utils/tests"
	"github.com/pingcap/dbaas/billing2/utils/tests/datainit"
	"github.com/shopspring/decimal"
	"github.com/stretchr/testify/suite"
	"github.com/stripe/stripe-go/v76"
)

var taxModel = &paymentsub.TaxModel{}

func (*MockTaxStripeHandler) CalculateTax(billingInfo *forms.BillingInformation, subCode string, price decimal.Decimal) (*forms.StripeCalculateTaxResult, error) {
	if billingInfo.CountryCode == "JP" {
		rate := decimal.RequireFromString("0.1")
		return &forms.StripeCalculateTaxResult{
			Amount:            price.Mul(rate),
			Inclusive:         false,
			TaxAbilityReason:  "standard",
			Country:           billingInfo.CountryCode,
			PercentageDecimal: rate.Mul(decimal.NewFromInt(100)).String(),
			State:             billingInfo.State,
			TaxType:           string(stripe.TaxRateTaxTypeSalesTax),
		}, nil
	}
	rate := decimal.RequireFromString("0.07")
	return &forms.StripeCalculateTaxResult{
		Amount:            price.Mul(rate),
		Inclusive:         false,
		TaxAbilityReason:  "standard",
		Country:           billingInfo.CountryCode,
		PercentageDecimal: rate.Mul(decimal.NewFromInt(100)).String(),
		State:             billingInfo.State,
		TaxType:           string(stripe.TaxRateTaxTypeSalesTax),
	}, nil
}

func (*MockTaxStripeHandler) CreateTaxRate(rate *forms.TaxRate) (*forms.TaxRate, error) {
	if rate.Country == "JP" {
		rate.StripeTaxRateID = "jp"
	}
	rate.StripeTaxRateID = uuid.NewString()
	return rate, nil
}

func (*MockTaxStripeHandler) GetTaxRate(rateID string) (*forms.TaxRate, error) {
	if rateID == "jp" {
		return &forms.TaxRate{
			StripeTaxRateID:  rateID,
			Value:            decimal.NewFromInt(7),
			DisplayName:      "Sales Tax",
			TaxAbilityReason: "standard",
			Inclusive:        false,
			Country:          "JP",
			State:            "Tokyo",
			TaxType:          string(stripe.TaxRateTaxTypeSalesTax),
			TenantID:         1,
			TaxCode:          config.Get().GetString(config.TiDBCloudStripeProductTaxCode),
		}, nil
	}
	return &forms.TaxRate{
		StripeTaxRateID:  rateID,
		Value:            decimal.NewFromInt(7),
		DisplayName:      "Sales Tax",
		TaxAbilityReason: "standard",
		Inclusive:        false,
		Country:          "US",
		State:            "CA",
		TaxType:          string(stripe.TaxRateTaxTypeSalesTax),
		TenantID:         1,
		TaxCode:          config.Get().GetString(config.TiDBCloudStripeProductTaxCode),
	}, nil
}

type TaxTestSuite struct {
	tests.BillingTestSuite
}

func TestTaxSuite(t *testing.T) {
	suite.Run(t, new(TaxTestSuite))
}

func (suite *TaxTestSuite) SetupTest() {
	suite.BillingTestSuite.SetupTest()
	datainit.CreateBillingConfig(1, entity.BillingConfigType_DirectCustomer)
	config.Get().Set(config.EnableTaxCalculation, true)
	MockCentralHandler()
	MockPaymentHandler()
}

func (suite *TaxTestSuite) TearDownTest() {
	suite.BillingTestSuite.TearDownTest()
	config.Get().Set(config.EnableTaxCalculation, false)
}

func (suite *TaxTestSuite) TestDesignatedTaxAddress() {
	assert := suite.Assert()
	err := billingInfoModel.CreateBillingCompany(&forms.BillingCompany{
		CompanyKey:     config.Get().GetString(config.DefaultBillingCompanyKey),
		Name:           "PINGCAP",
		PaymentSubCode: "",
	})
	assert.NoError(err)
	jpKey := "pingcap-jp"
	err = billingInfoModel.CreateBillingCompany(&forms.BillingCompany{
		CompanyKey:     jpKey,
		Name:           "PINGCAP Japan",
		PaymentSubCode: "32333",
	})
	assert.NoError(err)
	tenantID := uint(1)
	info, err := billingInfoModel.CreateDefaultBillingInfo(tenantID, &forms.BillingInformation{
		BillingAddress: forms.BillingAddress{
			CountryCode: "US",
			State:       "CA",
		},
	})
	assert.Equal(decimal.RequireFromString("7"), info.TaxRate.Value)
	_, err = billingInfoModel.UpdateTenantBillingCompany(tenantID, &forms.TenantBillingCompany{TenantID: tenantID, CompanyKey: jpKey})
	assert.NoError(err)
	taxRate, err := taxModel.RetrieveAndUpdateTenantTaxRate(tenantID)
	assert.NoError(err)
	assert.Equal(decimal.NewFromInt(7), taxRate.Value)
	err = db.GetDB().Exec("update billing_companies set designated_tax_address = '{\"country_code\":\"JP\"}', using_designated_tax_address_to_calculate_tax_rate=1 where company_key = ?", jpKey).Error
	assert.NoError(err)
	_, err = billingInfoModel.UpdateTenantBillingCompany(tenantID, &forms.TenantBillingCompany{TenantID: tenantID, CompanyKey: jpKey})
	assert.NoError(err)
	taxRate, err = taxModel.RetrieveAndUpdateTenantTaxRate(tenantID)
	assert.NoError(err)
	assert.Equal(decimal.NewFromInt(10), taxRate.Value)
}
