package tests

import (
	"fmt"
	"net/http"
	"strconv"

	"github.com/pingcap/dbaas/billing2/handler/cloudmarketplacehandler"
	"github.com/pingcap/dbaas/billing2/utils/httpclient"

	"github.com/pingcap/dbaas/billing2/billing_errors"
	"github.com/pingcap/dbaas/billing2/config"
	"github.com/pingcap/dbaas/billing2/constant"
	"github.com/pingcap/dbaas/billing2/db/entity"
	"github.com/pingcap/dbaas/billing2/forms"
	"github.com/pingcap/dbaas/billing2/handler/centralhandler"
	"github.com/pingcap/dbaas/billing2/handler/paymenthandler"
	"github.com/stretchr/testify/mock"
)

type MockPaymentHandlerImpl struct {
	mockProvider *MockPaymentProviderImpl
}

type MockPaymentProviderImpl struct {
	mock.Mock
	paymenthandler.PaymentProvider
	paymenthandler.StripePaymentHandler
}

func (*MockPaymentProviderImpl) Setup(tenant *forms.Tenant) (string, error) {
	if tenant.TenantID == 210 {
		return "211", nil
	}
	return fmt.Sprintf("mock_%d", tenant.TenantID), nil
}

func (m *MockPaymentProviderImpl) Pay(paymentInfo *forms.PaymentMethod, billingCompany *forms.BillingCompany, invoice *forms.Invoice) (*forms.Invoice, error) {
	invoice.ChannelLoss = invoice.CostPrice.Sub(invoice.CostPrice.Truncate(0))
	return invoice, m.Called(paymentInfo, billingCompany, invoice).Error(0)
}

func (m *MockPaymentProviderImpl) PayMultiInvoice(paymentInfo *forms.PaymentMethod, billingCompany *forms.BillingCompany, invoices []forms.Invoice) ([]forms.Invoice, error) {
	for i := 0; i != len(invoices); i++ {
		invoices[i].ChannelLoss = invoices[i].CostPrice.Sub(invoices[i].CostPrice.Truncate(0))
	}
	return invoices, m.Called(paymentInfo, billingCompany, invoices).Error(0)
}

func (*MockPaymentProviderImpl) Payable(tenantID uint, userCode string) (bool, error) {
	return true, nil
}

func (m *MockPaymentProviderImpl) NeedMultiInvoiceSendOnce() bool {
	return m.Called().Bool(0)
}

func (m *MockPaymentProviderImpl) SetPaymentMethodDefault(userCode, methodId string) (*forms.StripePaymentMethod, error) {
	arguments := m.Called()
	paymentMethod, _ := arguments[0].(*forms.StripePaymentMethod)
	err, _ := arguments[1].(error)
	return paymentMethod, err
}

func (m *MockPaymentProviderImpl) GetThirdPartyName() string {
	return "mock"
}

func (m *MockPaymentProviderImpl) EnableReconciliation() bool {
	return false
}

func (m *MockPaymentProviderImpl) EnableTaxCalculation() bool {
	return config.Get().GetBool(config.EnableTaxCalculation)
}

func (m *MockPaymentHandlerImpl) GetProvider(string) (paymenthandler.PaymentProvider, error) {
	return m.mockProvider, nil
}

func (m *MockPaymentHandlerImpl) AllProviders() []string {
	return []string{"mock", entity.PaymentType_WireTransfer}
}

func MockPaymentHandler() {
	provider := &MockPaymentProviderImpl{}
	provider.On("Pay", mock.Anything, mock.Anything, mock.Anything).Return(nil)
	provider.On("NeedMultiInvoiceSendOnce").Return(false)
	provider.On("PayMultiInvoice", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(billing_errors.SystemError)
	paymenthandler.SetPaymentHandler(&MockPaymentHandlerImpl{
		mockProvider: provider,
	})
}

type MockCentralHandlerImpl struct {
	centralhandler.CentralHandler
}

func (*MockCentralHandlerImpl) GetTenant(tenantID uint) (*forms.Tenant, error) {
	if tenantID == 100 {
		return &forms.Tenant{
			TenantID:                  tenantID,
			ThirdPartyAccountProvider: constant.MSPAccountProvider,
			Status:                    centralhandler.TenantStatusActive,
		}, nil
	}
	return &forms.Tenant{
		TenantID:                  tenantID,
		ThirdPartyAccountProvider: constant.GCPAccountProvider,
		Status:                    centralhandler.TenantStatusActive,
	}, nil
}

func (*MockCentralHandlerImpl) GetAllTenants() ([]forms.Tenant, error) {
	return []forms.Tenant{}, nil
}

func (*MockCentralHandlerImpl) DownloadFile(string) ([]byte, error) {
	return []byte("mock_file_content"), nil
}

func (*MockCentralHandlerImpl) GetUser(userID uint) (*forms.User, error) {
	return &forms.User{
		UserID: userID,
	}, nil
}

func (*MockCentralHandlerImpl) GetProjectName(projectID uint) (string, error) {
	return strconv.FormatUint(uint64(projectID), 10), nil
}

func (*MockCentralHandlerImpl) GetProjectInfo(projectID uint) (*forms.Project, error) {
	return &forms.Project{
		ID:   projectID,
		Name: strconv.FormatUint(uint64(projectID), 10),
	}, nil
}

func (*MockCentralHandlerImpl) GetMspCustomerScheduleInfo(customerID uint) (*forms.MspCustomerScheduleInfo, error) {
	if customerID == 100 {
		return &forms.MspCustomerScheduleInfo{
			CustomerTenantID: uint64(customerID),
			MspTenantID:      1,
			//EffectedAt:       BillingDate.AddDate(0, 1, 0),
		}, nil
	}
	return nil, billing_errors.ObjectNotExistsError
}

func MockCentralHandler() {
	centralhandler.SetCentralHandler(&MockCentralHandlerImpl{})
}

type MockCloudMarketplaceImpl struct {
	mockProvider *MockAzureMarketplaceImpl
}

func (m *MockCloudMarketplaceImpl) GetMarketplace(provider string) (cloudmarketplacehandler.MarketplaceProvider, error) {
	return m.mockProvider, nil
}

type MockAzureMarketplaceImpl struct {
	mock.Mock
	cloudmarketplacehandler.MarketplaceHandler
}

func (m MockAzureMarketplaceImpl) GetToken() (string, error) {
	return "test", nil
}
func azureAuth(req *http.Request) error {
	return nil
}
func (m MockAzureMarketplaceImpl) GetAPIClient() httpclient.HTTPClient {
	return httpclient.NewClient(azureAuth, "", "")

}

func (m MockAzureMarketplaceImpl) GetSubscription(subscriptionID string) (forms.SubscriptionDetails, error) {
	return forms.SubscriptionDetails{}, nil

}

func (m MockAzureMarketplaceImpl) CancelSubscription(subscriptionID string) error {
	return nil

}

func (m MockAzureMarketplaceImpl) GetSubscriptionsByAzureSubscriptionID(subscriptionID string, isSubscribed bool) (forms.SubscriptionList, error) {
	return forms.SubscriptionList{Subscriptions: []forms.SubscriptionDetails{forms.SubscriptionDetails{Id: "s"}}}, nil

}

func (m MockAzureMarketplaceImpl) GetSubscriptionListByStatus(Status map[string]bool) (map[string]string, error) {
	return nil, nil

}

func (m MockAzureMarketplaceImpl) GetSubscriptionList() (subscriptionList forms.SubscriptionList, err error) {
	return subscriptionList, nil

}

func (m MockAzureMarketplaceImpl) ActivateSubscription(subscriptionID string) error {
	return nil
}

func MockMarketplaceHandler() {
	provider := &MockAzureMarketplaceImpl{}
	provider.On("", mock.Anything, mock.Anything, mock.Anything).Return(nil)
	cloudmarketplacehandler.SetMarketplaceHandler(&MockCloudMarketplaceImpl{
		mockProvider: provider,
	})
}
