package reconciliation

import (
	"time"

	"github.com/pingcap/dbaas/billing2/config"
	"github.com/pingcap/dbaas/billing2/db/entity"
	"github.com/pingcap/dbaas/billing2/model/payment"
	"github.com/pingcap/dbaas/billing2/utils/log"
	"github.com/pingcap/dbaas/billing2/utils/timeutils"
	"github.com/shopspring/decimal"
	"go.uber.org/zap"
)

type TenantReconciliationInvoice struct {
	TenantID        uint
	Invoice         decimal.Decimal
	PaymentMethodID uint
	InvoiceDetail   map[string]decimal.Decimal
}

func getTotalInvoice(date time.Time, nextDate time.Time, paymentType string) ([]*TenantReconciliationInvoice, error) {
	var err error
	switch paymentType {
	case entity.PaymentType_GCP:
		offset := config.Get().GetDuration(config.GCPReconciliationOffsetHour) * time.Hour
		date = date.Add(offset)
		nextDate = nextDate.Add(offset)
		log.Info("gcp reconciliation, enable offset", zap.Duration("offset", offset))
	}
	log.Info("start to retrieve monthly aggregated invoices", zap.Time("date", date), zap.Time("nextDate", nextDate), zap.String("paymentType", paymentType))
	monthlyInvoices, err := (&payment.InvoiceModel{}).GetMonthlyAggregateInvoicesByPaymentType(date, nextDate, paymentType)
	if err != nil {
		return nil, err
	}
	var ret []*TenantReconciliationInvoice
	for _, row := range monthlyInvoices {
		if len(ret) == 0 || ret[len(ret)-1].TenantID != row.TenantID || ret[len(ret)-1].PaymentMethodID != row.PaymentMethodID {
			ret = append(ret, &TenantReconciliationInvoice{
				TenantID:        row.TenantID,
				Invoice:         decimal.Zero,
				PaymentMethodID: row.PaymentMethodID,
				InvoiceDetail:   map[string]decimal.Decimal{},
			})
		}
		ti := ret[len(ret)-1]
		ti.Invoice = ti.Invoice.Add(row.Invoice)
		if _, ok := ti.InvoiceDetail[row.InvoiceMonth]; !ok {
			ti.InvoiceDetail[row.InvoiceMonth] = decimal.Zero
		}
		ti.InvoiceDetail[row.InvoiceMonth] = ti.InvoiceDetail[row.InvoiceMonth].Add(row.Invoice)
	}
	return ret, nil
}

func GetDailyTotalInvoice(checkDate time.Time, paymentType string) ([]*TenantReconciliationInvoice, error) {
	s := timeutils.GetDayDate(checkDate)
	e := s.AddDate(0, 0, 1)
	return getTotalInvoice(s, e, paymentType)
}

func GetMonthlyTotalInvoice(checkDate time.Time, paymentType string) ([]*TenantReconciliationInvoice, error) {
	s := timeutils.GetMonthDate(checkDate)
	e := s.AddDate(0, 1, 0)
	return getTotalInvoice(s, e, paymentType)
}
