package dao

import (
	"fmt"
	"github.com/civet148/log"
	"github.com/civet148/sqlca/v2"
	"intent-system/pkg/dal/models"
)

type InviteCodeCondition struct {
	RandomCode string `json:"invite_code"`
	Account    string `json:"account"`
	State      int    `json:"state"`
	PageNo     int    `json:"page_no"`
	PageSize   int    `json:"page_size"`
}

const (
	InviteCodeStateUnused = 1 //等待校验
	InviteCodeStateUsed   = 2 //已校验
)

type InviteCodeDAO struct {
	db *sqlca.Engine
}

func NewInviteCodeDAO(db *sqlca.Engine) *InviteCodeDAO {
	return &InviteCodeDAO{
		db: db,
	}
}

// insert if not exist or update columns on duplicate key...
func (dao *InviteCodeDAO) Upsert(do *models.InviteCodeDO, columns ...string) (lastInsertId int64, err error) {
	return dao.db.Model(&do).Table(models.TableNameInviteCode).Select(columns...).Upsert()
}

// query records by id
func (dao *InviteCodeDAO) QueryById(id interface{}, columns ...string) (do *models.InviteCodeDO, err error) {
	if _, err = dao.db.Model(&do).Table(models.TableNameInviteCode).Id(id).Select(columns...).Query(); err != nil {
		return nil, err
	}
	return
}

// query records by conditions
func (dao *InviteCodeDAO) QueryByCondition(conditions map[string]interface{}, columns ...string) (dos []*models.InviteCodeDO, err error) {
	if len(conditions) == 0 {
		return nil, fmt.Errorf("condition must not be empty")
	}
	e := dao.db.Model(&dos).Table(models.TableNameInviteCode).Select(columns...)
	for k, v := range conditions {
		e.Eq(k, v)
	}
	if _, err = e.Query(); err != nil {
		return nil, err
	}
	return
}

func (dao *InviteCodeDAO) CheckInviteCodeValid(strRandomCode string) (ok bool, err error) {
	var do *models.InviteCodeDO
	_, err = dao.db.Model(&do).
		Table(models.TableNameInviteCode).
		Equal(models.INVITE_CODE_COLUMN_RANDOM_CODE, strRandomCode).
		Equal(models.INVITE_CODE_COLUMN_STATE, InviteCodeStateUnused).
		Equal(models.INVITE_CODE_COLUMN_DELETED, 0).
		Query()
	if err != nil {
		return false, log.Errorf(err.Error())
	}
	if do.Id == 0 {
		return false, nil
	}
	if do.UserId != 0 && do.State == InviteCodeStateUsed {
		return false, nil
	}
	return true, nil
}

func (dao *InviteCodeDAO) CheckUserInviteCode(strUserAcc, strRandomCode string) (ok bool, err error) {
	var do *models.InviteCodeDO
	_, err = dao.db.Model(&do).
		Table(models.TableNameInviteCode).
		Equal(models.INVITE_CODE_COLUMN_USER_ACC, strUserAcc).
		Equal(models.INVITE_CODE_COLUMN_RANDOM_CODE, strRandomCode).
		Equal(models.INVITE_CODE_COLUMN_DELETED, 0).
		Query()
	if err != nil {
		return false, log.Errorf(err.Error())
	}
	if do.Id == 0 {
		return false, nil
	}
	if do.State == InviteCodeStateUsed {
		return false, nil
	}
	return true, nil
}

func (dao *InviteCodeDAO) Insert(do *models.InviteCodeDO) (lastId int64, err error) {
	var id int32
	_, err = dao.db.Model(&id).
		Table(models.TableNameInviteCode).
		Equal(models.INVITE_CODE_COLUMN_RANDOM_CODE, do.RandomCode).
		Query()
	if err != nil {
		return 0, log.Errorf(err.Error())
	}
	if id != 0 {
		return 0, log.Errorf("invite code already exists")
	}
	if lastId, err = dao.db.Model(&do).Table(models.TableNameInviteCode).Insert(); err != nil {
		log.Errorf(err.Error())
		return
	}
	return
}

func (dao *InviteCodeDAO) Update(do *models.InviteCodeDO, columns ...string) (lastId int64, err error) {
	if lastId, err = dao.db.Model(&do).
		Table(models.TableNameInviteCode).
		Select(columns...).
		Update(); err != nil {
		log.Errorf(err.Error())
		return
	}
	return
}

func (dao *InviteCodeDAO) UpdateByUserAndInviteCode(strUserAcc, strRandomCode string) (lastId int64, err error) {
	if lastId, err = dao.db.Model(InviteCodeStateUsed).
		Table(models.TableNameInviteCode).
		Select(models.INVITE_CODE_COLUMN_STATE).
		Equal(models.INVITE_CODE_COLUMN_USER_ACC, strUserAcc).
		Equal(models.INVITE_CODE_COLUMN_RANDOM_CODE, strRandomCode).
		Equal(models.INVITE_CODE_COLUMN_DELETED, 0).
		Update(); err != nil {
		log.Errorf(err.Error())
		return
	}
	return
}
func (dao *InviteCodeDAO) DeleteById(id int32) (lastId int64, err error) {
	if lastId, err = dao.db.Model(1).
		Select(models.INVITE_CODE_COLUMN_DELETED).
		Table(models.TableNameInviteCode).
		Equal(models.INVITE_CODE_COLUMN_ID, id).
		Update(); err != nil {
		log.Errorf(err.Error())
		return
	}
	return
}

func (dao *InviteCodeDAO) DeleteByInviteCodeUnused(strRandomCode string) (lastId int64, err error) {
	if lastId, err = dao.db.Model(1).
		Select(models.INVITE_CODE_COLUMN_DELETED).
		Table(models.TableNameInviteCode).
		Equal(models.INVITE_CODE_COLUMN_STATE, InviteCodeStateUnused).
		Equal(models.INVITE_CODE_COLUMN_RANDOM_CODE, strRandomCode).
		Equal(models.INVITE_CODE_COLUMN_DELETED, 0).
		Update(); err != nil {
		log.Errorf(err.Error())
		return
	}
	return
}

func (dao *InviteCodeDAO) DeleteUnusedCodeByUserAcc(strUserAcc string) (lastId int64, err error) {
	if lastId, err = dao.db.Model(1).
		Select(models.INVITE_CODE_COLUMN_DELETED).
		Table(models.TableNameInviteCode).
		Equal(models.INVITE_CODE_COLUMN_STATE, InviteCodeStateUnused).
		Equal(models.INVITE_CODE_COLUMN_USER_ACC, strUserAcc).
		Update(); err != nil {
		log.Errorf(err.Error())
		return
	}
	return
}

func (dao *InviteCodeDAO) SelectByCondition(cond *InviteCodeCondition) (dos []*models.InviteCodeDO, total int64, err error) {
	e := dao.db.Model(&dos).
		Table(models.TableNameInviteCode).
		Page(cond.PageNo, cond.PageSize).
		Desc(models.INVITE_CODE_COLUMN_CREATED_TIME).
		Equal(models.INVITE_CODE_COLUMN_DELETED, 0)

	if cond.RandomCode != "" {
		e.Equal(models.INVITE_CODE_COLUMN_RANDOM_CODE, cond.RandomCode)
	}
	if cond.Account != "" {
		e.Equal(models.INVITE_CODE_COLUMN_USER_ACC, cond.Account)
	}
	if cond.State != 0 {
		e.Equal(models.INVITE_CODE_COLUMN_STATE, cond.State)
	}
	_, total, err = e.QueryEx()
	if err != nil {
		log.Errorf(err.Error())
		return
	}
	return
}

func (dao *InviteCodeDAO) SelectByAccAndCode(strUserAcc, strRandomCode string) (do *models.InviteCodeDO, err error) {
	_, err = dao.db.Model(&do).
		Table(models.TableNameInviteCode).
		Equal(models.INVITE_CODE_COLUMN_DELETED, 0).
		Equal(models.INVITE_CODE_COLUMN_USER_ACC, strUserAcc).
		Equal(models.INVITE_CODE_COLUMN_RANDOM_CODE, strRandomCode).
		Equal(models.INVITE_CODE_COLUMN_DELETED, 0).
		Query()
	if err != nil {
		log.Errorf(err.Error())
		return
	}
	return
}
