package workerhandler

import (
	"encoding/json"
	"fmt"
	"github.com/pingcap/dbaas/billing2/db"
	"github.com/pingcap/dbaas/billing2/db/entity"
	"github.com/pingcap/dbaas/billing2/utils/log"
	"github.com/pingcap/dbaas/billing2/utils/timeutils"
	"go.uber.org/zap"
	"strconv"
	"time"
)

type Workerhandler interface {
	DedupeRun(tenantID uint, workName string, runningInterval string, startTime time.Time, workerRunFunc WorkerRun) bool
	WorkerDuplicateCheck(tenantID uint, workName string, runningInterval string, startTime time.Time) (string, bool)
	WorkerRunningRecordInsertDb(tenantID uint, workName string, workerKey string, param interface{}) error
}
type HandlerImpl struct{}

var global Workerhandler = &HandlerImpl{}

func Get() Workerhandler {
	return global
}

type WorkerRun func(tenantID uint, startTime time.Time) (interface{}, error)

func (w *HandlerImpl) DedupeRun(tenantID uint, workName string, runningInterval string, startTime time.Time, workerRunFunc WorkerRun) bool {
	workerKey, isDuplicate := w.WorkerDuplicateCheck(tenantID, workName, runningInterval, startTime)

	if !isDuplicate {
		param, err := workerRunFunc(tenantID, startTime)
		if err != nil {
			log.Error("workerRunFunc failed ", zap.Error(err), zap.String("workName", workName), zap.Uint("TenantID", tenantID))
			return false
		}
		err = w.WorkerRunningRecordInsertDb(tenantID, workName, workerKey, param)
		if err != nil {
			return false
		}
	}
	return true

}

func (w *HandlerImpl) WorkerDuplicateCheck(tenantID uint, workName string, runningInterval string, startTime time.Time) (string, bool) {
	// workerKey = workerName- + workerInterval- + tenantId- + year +month
	var workerKey string
	switch runningInterval {
	case timeutils.HOUR:
		workerKey = fmt.Sprintf("%s-%s-%s-%s ", workName, runningInterval, strconv.FormatUint(uint64(tenantID), 10), startTime.Format("2006-01-02 15"))
	case timeutils.DAY:
		workerKey = fmt.Sprintf("%s-%s-%s-%s ", workName, runningInterval, strconv.FormatUint(uint64(tenantID), 10), startTime.Format("2006-01-02"))

	case timeutils.MONTH:
		workerKey = fmt.Sprintf("%s-%s-%s-%s ", workName, runningInterval, strconv.FormatUint(uint64(tenantID), 10), startTime.Format("2006-01"))

	}
	entityCount, err := entity.NewWorkerRunningRecordQuerySet(db.GetDB()).TenantIDEq(tenantID).WorkerKeyEq(workerKey).Count()

	if err != nil {
		
		log.Error("WorkerDuplicateCheck failed ", zap.Error(err), zap.String("workName", workName), zap.Uint("TenantID", tenantID))
		return workerKey, true
	}
	if entityCount > 0 {
		return workerKey, true
	}
	return workerKey, false

}
func (w *HandlerImpl) WorkerRunningRecordInsertDb(tenantID uint, workName string, workerKey string, param interface{}) error {
	var runningParam string

	if nil != param {
		jsonData, err := json.Marshal(param)
		if err != nil {
			runningParam = "json.Marshal(syncParam) err "
			log.Info(" json.Marshal(syncParam) err ", zap.String("workName", workName), zap.Error(err), zap.Uint("TenantID", tenantID))

		} else {
			runningParam = string(jsonData)
		}
	}
	entity := entity.WorkerRunningRecord{
		TenantID:     tenantID,
		WorkerName:   workName,
		WorkerKey:    workerKey,
		RunningParam: runningParam,
	}
	err := entity.Create(db.GetDB())
	if err != nil {
		log.Error("entity.Create(db.GetDB()) err ", zap.String("workName", workName), zap.Error(err), zap.Uint("TenantID", tenantID))
		return err
	}
	return nil
}
