package utils

import (
	"bytes"
	"encoding/gob"
	"fmt"
	"github.com/go-pg/pg/v10/orm"
	"github.com/linmadan/egglib-go/utils/snowflake"
	"strconv"
	"time"
)

var (
	ERR_EMPTY_TC = fmt.Errorf("transactionContext参数不能为nil")
)

type Query struct {
	*orm.Query
	queryOptions map[string]interface{}
	AffectRow    int
}

func NewQuery(query *orm.Query, queryOptions map[string]interface{}) *Query {
	return &Query{
		query,
		queryOptions,
		0,
	}
}

func (query *Query) SetWhere(condition, key string) *Query {
	if v, ok := query.queryOptions[key]; ok {
		if t, e := time.Parse(time.RFC3339, fmt.Sprintf("%v", v)); e == nil {
			if t.IsZero() {
				return query
			}
		}
		query.Where(condition, v)
	}
	return query
}

func (query *Query) SetUpdate(condition, key string) *Query {
	if v, ok := query.queryOptions[key]; ok {
		query.Set(condition, v)
	}
	return query
}

func (query *Query) SetLimit() *Query {
	if offset, ok := query.queryOptions["offset"]; ok {
		offset, _ := strconv.ParseInt(fmt.Sprintf("%v", offset), 10, 64)
		if offset > -1 {
			query.Offset(int(offset))
		}
	} else {
		query.Offset(0)
	}
	if limit, ok := query.queryOptions["limit"]; ok {
		limit, _ := strconv.ParseInt(fmt.Sprintf("%v", limit), 10, 64)
		if limit > -1 {
			query.Limit(int(limit))
		} else {
			query.Limit(20)
		}
	}
	return query
}

func (query *Query) SetOrder(orderColumn string, key string) *Query {
	//query.Order(condition...)
	//return query
	if v, ok := query.queryOptions[key]; ok {
		query.Order(fmt.Sprintf("%v %v", orderColumn, v))
	}
	return query
}

func (query *Query) HandleError(err error, errMsg string) error {
	if err.Error() == "pg: no rows in result set" {
		return fmt.Errorf(errMsg)
	} else {
		return err
	}
}

func NewSnowflakeId() (int64, error) {
	IdWorker, err := snowflake.NewIdWorker(2)
	if err != nil {
		return 0, err
	}
	id, err := IdWorker.NextId()
	return id, err
}

//GobModelTransform 模型转换
func GobModelTransform(dst interface{}, src interface{}) error {
	var data bytes.Buffer
	enc := gob.NewEncoder(&data)
	if err := enc.Encode(src); err != nil {
		return err
	}
	dec := gob.NewDecoder(&data)
	if err := dec.Decode(dst); err != nil {
		return err
	}
	return nil
}