package queries

import (
	"fmt"
	"time"

	"github.com/fiskerinc/cloud-services/pkg/common"
	"github.com/fiskerinc/cloud-services/pkg/validator"
	"github.com/go-pg/pg/v10/orm"
	"github.com/pkg/errors"
)

type APITokensInterface interface {
	Delete(token string) (orm.Result, error)
	Insert(apitoken common.APIToken) (orm.Result, error)
	Update(apitoken *common.APIToken) (orm.Result, error)
	Get(token string) (*common.APIToken, error)
	Select(apitoken *common.APIToken, paging *PageQueryOptions) ([]common.APIToken, error)
	Count(apitoken *common.APIToken) (int, error)
}

type APITokens struct {
	QueryBase
}

func (kv *APITokens) Delete(token string) (orm.Result, error) {
	if token == "" {
		return nil, errors.WithStack(&validator.FieldError{
			ErrorMsg: "token required",
		})
	}

	conn := kv.GetDBConn()
	result, err := conn.Model(&common.APIToken{
		Token: token,
	}).WherePK().Delete()

	return result, errors.WithStack(err)
}

func (kv *APITokens) Insert(apiToken common.APIToken) (orm.Result, error) {
	err := validator.ValidateStruct(apiToken)
	if err != nil {
		return nil, errors.WithStack(err)
	}

	return kv.insert(&apiToken)
}

func (kv *APITokens) Get(token string) (*common.APIToken, error) {
	if token == "" {
		return nil, errors.WithStack(&validator.FieldError{
			ErrorMsg: "token required",
		})
	}

	keyvalues := []common.APIToken{}
	err := kv.GetDBConn().
		Model(&keyvalues).
		Where("token = ?", token).
		Where("expires_at > ? or expires_at is null", time.Now()).
		Select()
	if err != nil {
		return nil, errors.WithStack(err)
	}

	if len(keyvalues) == 0 {
		return nil, errors.New("token not found")
	}

	return &keyvalues[0], nil
}

func (kv *APITokens) selectFilter(query *orm.Query, filter *common.APIToken) {
	if filter.Token != "" {
		query.Where("token = ?", filter.Token)
	}

	if filter.Roles != "" {
		query.Where("roles LIKE ?", fmt.Sprintf("%%%s%%", filter.Roles))
	}

	if filter.Description != "" {
		query.Where("description = ?", filter.Description)
	}

}

func (kv *APITokens) Select(filter *common.APIToken, paging *PageQueryOptions) ([]common.APIToken, error) {
	items := []common.APIToken{}
	query := kv.GetDBConn().Model(&items)

	kv.selectFilter(query, filter)
	if paging != nil {
		kv.pageQuery(query, paging)
	}

	err := query.Select()

	return items, errors.WithStack(err)
}

func (kv *APITokens) Update(model *common.APIToken) (orm.Result, error) {
	return kv.update(model)
}

func (kv *APITokens) Count(apitoken *common.APIToken) (int, error) {
	return kv.count(apitoken)
}
