package repoter

import (
	"context"
	"strconv"

	"github.com/tidbcloud/metering/pkg/common/config"
	"github.com/tidbcloud/metering/pkg/common/models"
	"go.uber.org/zap"
)

// repoter send billing repoter to sqs, and save checkpoint to azure blob
type BillingRepoter struct {
	loader BillingRepoterLoader
	conf   *config.ServiceConfig
	sender MeasureSender
	log    *zap.Logger
}

func NewBillingRepoter(conf *config.ServiceConfig, log *zap.Logger) (*BillingRepoter, error) {
	loader, err := NewBillingRepoterLoad(conf).Init()
	if err != nil {
		return nil, err
	}
	var sender MeasureSender = new(MeasureAPIImpl)
	err = sender.InitMeasureHandler(conf.Env, conf.Vendor, true, true)
	if err != nil {
		return nil, err
	}
	return &BillingRepoter{
		loader: loader,
		conf:   conf,
		sender: sender,
		log:    log,
	}, nil
}
func (b *BillingRepoter) SetSender(sender MeasureSender) {
	b.sender = sender
}

func (b *BillingRepoter) Report(ctx context.Context, objectname string) error {
	chekpoint, err := b.loader.LoadCheckpoint(ctx, objectname)
	if err != nil {
		b.log.Error("load checkpoint failed", zap.Error(err))
		return err
	}
	// load repoter
	repoters, err := b.loader.LoadRepoterWithTs(ctx, objectname, chekpoint)
	if err != nil {
		b.log.Error("load repoter failed", zap.Error(err))
		return err
	}
	first := true
	//send to Billing sqs
	for _, repoter := range repoters {
		if repoter.CreatedAt > chekpoint {
			chekpoint = repoter.CreatedAt
		}
		ok := b.skipRepoter(repoter)
		if ok {
			if first {
				first = false
				b.log.Info("skip report beacause switch time", zap.Int64("metering time", repoter.CostTimestamp), zap.Int64("switch time", b.conf.TrafficMeteringConfig.BillingReportSwitchTime))
			}
			continue
		}
		err = b.sender.SendMeasure(ctx, *repoter)
		if err != nil {
			b.log.Error("send measure failed", zap.Error(err))
			return err
		}
	}
	// update checkpoint
	err = b.loader.SaveCheckpoint(ctx, objectname, chekpoint)
	if err != nil {
		b.log.Error("save checkpoint failed", zap.Error(err))
		return err
	}
	return nil
}

func (b *BillingRepoter) skipRepoter(repoter *models.BillingReport) bool {
	if repoter.CostTimestamp < b.conf.TrafficMeteringConfig.BillingReportSwitchTime {
		tenantid := strconv.FormatUint(repoter.TenantID, 10)
		for _, v := range b.conf.TrafficMeteringConfig.TenantWithSwitchTimes {
			if v.TenantId == tenantid && repoter.CostTimestamp >= v.SwitchTime {
				b.log.Info("send to billing because tenantid in whitelist and time catched", zap.String("tenantid", tenantid), zap.Int64("tenant switch time", v.SwitchTime), zap.Int64("repoter time", repoter.CostTimestamp))
				return false
			}
		}
		return true
	}
	return false
}
