package repository

import (
	"cron_admin/app/http/entities"
	"cron_admin/app/models"
	"cron_admin/app/utils"
	"cron_admin/app/utils/mapstructure"
	"github.com/pkg/errors"
	"github.com/qit-team/snow-core/db"
	"time"
	"xorm.io/builder"
	"xorm.io/xorm"
)

type CommonRepo[P models.PO] struct {
	repo *xorm.Session
}

type ExtraCommonRepo[P models.PO, T any] struct {
	repo *xorm.Session
}

type ICommonRepo[P models.PO] interface {
	GetSession() *xorm.Session
	FindAll(list *[]P, opts ...DBOption) error
	FindAndCount(list *[]P, opts ...DBOption) (int64, error)
	Get(db *P, opts ...DBOption) (bool, error)
	Update(db *P, opts ...DBOption) (int64, error)
	Delete(db *P, opts ...DBOption) (int64, error)
	InsertOne(db *P, opts ...DBOption) (int64, error)
	InsertBatch(db *[]P, opts ...DBOption) (int64, error)

	WithSession(session *xorm.Session) ICommonRepo[P]
	WithByID(id uint) DBOption
	WithByDate(startTime, endTime time.Time) DBOption
	WithByUpdateDate(startTime, endTime time.Time) DBOption
	WithByStartDate(startTime time.Time) DBOption
	WithByEndDate(startTime time.Time) DBOption
	WithDesc(orderStr string) DBOption
	WithByStatus(status int) DBOption
	WithIdsIn(ids []uint) DBOption
	WithPage(pageFilter entities.PageRequest) DBOption
}

func NewCommonRepo[P models.PO]() ICommonRepo[P] {
	return &CommonRepo[P]{}
}

func (this *CommonRepo[P]) WithSession(session *xorm.Session) ICommonRepo[P] {
	this.repo = session
	return this
}

func (this *CommonRepo[P]) GetSession() *xorm.Session {
	return this.repo
}

func (this *CommonRepo[P]) FindAll(list *[]P, opts ...DBOption) error {
	return getDb(this.repo, opts...).Find(list)
}

func (this *CommonRepo[P]) FindAndCount(list *[]P, opts ...DBOption) (int64, error) {
	return getDb(this.repo, opts...).FindAndCount(list)
}

func (this *CommonRepo[P]) Get(db *P, opts ...DBOption) (bool, error) {
	return getDb(this.repo, opts...).Get(db)
}

func (this *CommonRepo[P]) Update(db *P, opts ...DBOption) (int64, error) {
	if len(opts) == 0 {
		return 0, errors.New("不允许不带条件的更新")
	}
	return getDb(this.repo, opts...).Update(db)
}

// 不允许不带条件的删除
func (this *CommonRepo[P]) Delete(db *P, opts ...DBOption) (int64, error) {
	if len(opts) == 0 {
		return 0, errors.New("不允许不带条件的删除")
	}
	return getDb(this.repo, opts...).Delete(db)
}

func (this *CommonRepo[P]) InsertOne(db *P, opts ...DBOption) (int64, error) {
	return getDb(this.repo, opts...).Insert(db)
}

// 批量插入
func (this *CommonRepo[P]) InsertBatch(db *[]P, opts ...DBOption) (int64, error) {
	return getDb(this.repo, opts...).Insert(db)
}

func getDb(repo *xorm.Session, opts ...DBOption) *xorm.Session {
	if repo == nil {
		repo = db.GetDb().NewSession()

	}
	for _, opt := range opts {
		repo = opt(repo)
	}
	return repo
}

func InAndToMap[P models.PO, T string | int](engin *xorm.EngineGroup, key string, values []T) (map[T]*P, error) {

	var (
		results     []*P
		resultSlice []map[string]interface{}
	)
	cond := builder.NewCond()

	cond = cond.And(builder.Eq{key: values})

	err := engin.Where(cond).Find(&results)
	if err != nil {
		return nil, err
	}
	for _, v := range results {
		var resultsm map[string]interface{}
		mapstructure.Decode(v, &resultsm)
		resultSlice = append(resultSlice, resultsm)
	}

	resultMap := make(map[T]*P, len(resultSlice))

	for _, v := range resultSlice {
		keyC := utils.SnakeToCamel(key)
		if _, exist := v[keyC]; !exist {
			resultMap = nil
			break
		}
		if v[keyC] == nil || v[keyC] == "" {
			continue
		}
		var vToP P
		mapstructure.Decode(v, &vToP)
		keyValue := v[keyC].(T)
		resultMap[keyValue] = &vToP
	}

	return resultMap, nil
}