package salesforcehandler

import (
	"errors"

	"github.com/pingcap/dbaas/billing2/billing_errors"
	"github.com/pingcap/dbaas/billing2/config"
	"github.com/pingcap/dbaas/billing2/utils/log"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promauto"
	"github.com/shopspring/decimal"
	"go.uber.org/zap"
)

type Account struct {
	Plan             string `json:"plan"`
	PortalID         string `json:"portal_id"`
	BillingEmail     string `json:"billing_email"`
	BindCreditCardAt string `json:"bind_credit_card_at"`
	Source           string `json:"source"`
}

type POCCredits struct {
	PortalID         string          `json:"portal_id"`
	RemainingCredits decimal.Decimal `json:"remaining_credits"`
}
type MonthBills struct {
	OrgId           string          `json:"org_id"`
	BillStartDate   string          `json:"bill_start_date"`
	BillEndDate     string          `json:"bill_end_date"`
	TotalCost       decimal.Decimal `json:"total_cost"`
	IsOnlySeverLess bool            `json:"is_only_severLess"`
}
type Response struct {
	Message string `json:"message"`
	Code    string `json:"code"`
}

type SalesforceHandler interface {
	UpdateAccount(Account) error
	SyncPOCCredits(POCCredits) error
	SyncMarketUserMonthBills(MonthBills) error
}

const (
	syncLeadsApiPrefix          = "/services/apexrest/SyncLeads"
	updateAccountApiPrefix      = "/services/apexrest/UpdateAccount"
	syncPocApplicationApiPrefix = "/services/apexrest/addpocandresults"
	syncPOCCreditsApiPrefix     = "/services/apexrest/updateAccountRemaining"
	syncMonthBillsApiPrefix     = "services/apexrest/addbilling"
)

var salesforceMetrics = promauto.NewCounterVec(
	prometheus.CounterOpts{
		Namespace: "dbaas",
		Subsystem: "billing",
		Name:      "salesforce_call_counter",
		Help:      "number of call salesforce api",
	}, []string{"status"},
)

type salesforceHandlerImpl struct{}

var global SalesforceHandler = &salesforceHandlerImpl{}

func Get() SalesforceHandler {
	return global
}

func Set(salesfroceHandler SalesforceHandler) {
	global = salesfroceHandler
}

func (*salesforceHandlerImpl) UpdateAccount(account Account) (returnErr error) {
	if !config.Get().GetBool(config.EnableSalesforce) {
		return nil
	}

	defer func() {
		if returnErr != nil {
			log.Error("UpdateAccount failed to call salesforce", zap.Error(returnErr))
			salesforceMetrics.WithLabelValues("failed").Inc()
		} else {
			log.Info("UpdateAccount success call salesforce")
			salesforceMetrics.WithLabelValues("success").Inc()
		}
	}()
	result := &Response{}
	err := getClient().Request("POST", updateAccountApiPrefix, nil, account, result)
	if err != nil {
		return err
	}

	if result.Code != "0" {
		return billing_errors.NewSalesforceError(errors.New(result.Message))
	}
	return nil
}

func (*salesforceHandlerImpl) SyncPOCCredits(pocCredits POCCredits) (returnErr error) {
	if !config.Get().GetBool(config.EnableSalesforce) {
		return nil
	}

	defer func() {
		if returnErr != nil {
			log.Error("SyncPOCCredits failed to call salesforce", zap.Error(returnErr))
			salesforceMetrics.WithLabelValues("failed").Inc()
		} else {
			log.Info("SyncPOCCredits success call salesforce")
			salesforceMetrics.WithLabelValues("success").Inc()
		}
	}()
	result := &Response{}
	err := getClient().Request("POST", syncPOCCreditsApiPrefix, nil, pocCredits, result)
	if err != nil {
		return err
	}

	if result.Code != "0" {
		return billing_errors.NewSalesforceError(errors.New(result.Message))
	}
	return nil
}

func (*salesforceHandlerImpl) SyncMarketUserMonthBills(monthBills MonthBills) (returnErr error) {
	if !config.Get().GetBool(config.EnableSalesforce) {
		return nil
	}

	defer func() {
		if returnErr != nil {
			log.Error("SyncMarketUserMonthBills failed to call salesforce", zap.Error(returnErr))
			salesforceMetrics.WithLabelValues("failed").Inc()
		} else {
			log.Info("SyncMarketUserMonthBills success call salesforce")
			salesforceMetrics.WithLabelValues("success").Inc()
		}
	}()
	result := &Response{}
	err := getClient().Request("POST", syncMonthBillsApiPrefix, nil, monthBills, result)
	log.Info("SyncMarketUserMonthBills", zap.Any("result", result))
	if err != nil {
		return err
	}

	if result.Code != "0" {
		return billing_errors.NewSalesforceError(errors.New(result.Message))
	}
	return nil
}
