package repo

import (
	"time"

	relent "github.com/tidbcloud/devops/entity/release"
	"github.com/tidbcloud/devops/pkg/infra/utils/pointer"
	"github.com/tidbcloud/devops/pkg/infra/utils/repoopt"
)

var (
	ChangeOpts  cOpts
	ReleaseOpts rOpts
	TicketOpts  tOpts
)

type cOpts struct{}

func (_ cOpts) SelectIDOnly() repoopt.Option {
	return &repoopt.Select{
		Select: []string{"id"},
	}
}

func (_ cOpts) ReleaseIn(ids []uint64) repoopt.Option {
	return &repoopt.Filter[uint64]{
		Column: "release_id",
		Values: ids,
	}
}

func (_ cOpts) NameIn(names []string) repoopt.Option {
	return &repoopt.Filter[string]{
		Column: "name",
		Values: names,
	}
}

func (_ cOpts) StatusIn(statuses []relent.ChangeStatus) repoopt.Option {
	return &repoopt.Filter[relent.ChangeStatus]{
		Column: "status",
		Values: statuses,
	}
}

func (_ cOpts) ApprovalIs(apprID uint64) repoopt.Option {
	return &repoopt.Filter[uint64]{
		Column: "approval_id",
		Values: []uint64{apprID},
	}
}

func (_ cOpts) WithPager(page int, perPage int, defaultOrder bool) repoopt.Option {
	pager := &repoopt.Pager{
		Page:    page,
		PerPage: perPage,
	}
	if !defaultOrder {
		return pager
	}

	order := &repoopt.Order{
		Column: "created_at",
		Desc:   true,
	}
	return repoopt.Aggregate(pager, order)
}

type rOpts struct{}

func (o rOpts) IDIn(ids []uint64) repoopt.Option {
	return &repoopt.Filter[uint64]{
		Column: "id",
		Values: ids,
	}
}

func (o rOpts) NameIn(names []string) repoopt.Option {
	return &repoopt.Filter[string]{
		Column: "name",
		Values: names,
	}
}

func (o rOpts) StatusIn(statuses []relent.ReleaseStatus) repoopt.Option {
	return &repoopt.Filter[relent.ReleaseStatus]{
		Column: "status",
		Values: statuses,
	}
}

func (o rOpts) ReleaseBefore(t time.Time) repoopt.Option {
	return &repoopt.Filter[time.Time]{
		Column:      "window_start_at",
		LessOrEqual: pointer.Pointer(t),
	}
}

func (o rOpts) ReleaseAfter(t time.Time) repoopt.Option {
	return &repoopt.Filter[time.Time]{
		Column:       "window_end_at",
		LargeOrEqual: pointer.Pointer(t),
	}
}

func (o rOpts) WithPager(page int, perPage int, defaultOrder bool) repoopt.Option {
	pager := &repoopt.Pager{
		Page:    page,
		PerPage: perPage,
	}
	if !defaultOrder {
		return pager
	}

	order := &repoopt.Order{
		Column: "window_start_at",
		Desc:   true,
	}
	return repoopt.Aggregate(pager, order)
}

type tOpts struct{}

func (o tOpts) IDIn(ids []uint64) repoopt.Option {
	return &repoopt.Filter[uint64]{
		Column: "id",
		Values: ids,
	}
}

func (o tOpts) ReleaseIn(releaseName ...string) repoopt.Option {
	return &repoopt.Filter[string]{
		Column: "release_name",
		Values: releaseName,
	}
}

func (o tOpts) NameIn(names []string) repoopt.Option {
	return &repoopt.Filter[string]{
		Column: "name",
		Values: names,
	}
}

func (o tOpts) StatusIn(statuses []string) repoopt.Option {
	return &repoopt.Filter[string]{
		Column: "status",
		Values: statuses,
	}
}

func (o tOpts) WithPager(page int, perPage int) repoopt.Option {
	pager := &repoopt.Pager{
		Page:    page,
		PerPage: perPage,
	}

	return pager
}
