package clustermaintenance

import (
	"context"
	"fmt"

	maintent "github.com/tidbcloud/devops/entity/maintenance"

	baseapi "github.com/tidbcloud/devops/api"
	"github.com/tidbcloud/devops/pkg/infra/errs"
	"github.com/tidbcloud/devops/pkg/infra/utils/repoopt"
	cmxapi "github.com/tidbcloud/devops/pkg/service/clustermaintenance/api"
)

func (s *svc) ListOpsExecutionWindows(
	ctx context.Context,
	param cmxapi.ListOpsExecutionWindowParam,
) ([]*maintent.OpsExecutionWindow, int64, error) {
	param, err := param.Normalize()
	if err != nil {
		return nil, 0, errs.APIErrorNew(baseapi.ErrCodeInvalidArgument, err)
	}

	filterOpts := make([]repoopt.Option, 0, 1)
	if len(param.IDs) > 0 {
		filterOpts = append(filterOpts, &repoopt.Filter[uint64]{
			Column: "id",
			Values: param.IDs,
		})
	}

	listOpts := make([]repoopt.Option, 0, len(filterOpts)+2)
	listOpts = append(listOpts, filterOpts...)
	listOpts = append(listOpts,
		&repoopt.Order{
			Column: "updated_at",
			Desc:   true,
		},
	)
	if param.Page > 0 {
		listOpts = append(listOpts, &repoopt.Pager{
			Page:    int(param.Page),
			PerPage: int(param.PerPage),
		})
	}

	items, err := s.repo.OpsExecutionWindow.List(ctx, listOpts...)
	if err != nil {
		return nil, 0, err
	}
	total, err := s.repo.OpsExecutionWindow.Count(ctx, filterOpts...)
	if err != nil {
		return nil, 0, err
	}

	return items, total, nil
}

func (s *svc) GetOpsExecutionWindow(
	ctx context.Context,
	id uint64,
) (*maintent.OpsExecutionWindow, error) {
	return s.repo.OpsExecutionWindow.Get(ctx, id)
}

func (s *svc) CreateOpsExecutionWindow(
	ctx context.Context,
	param cmxapi.CreateOpsExecutionWindowParam,
) (*maintent.OpsExecutionWindow, error) {
	param, err := param.Normalize()
	if err != nil {
		return nil, errs.APIErrorNew(baseapi.ErrCodeInvalidArgument, err)
	}

	var window *maintent.OpsExecutionWindow
	err = s.dbp.Transaction(ctx, func(ctx context.Context) error {
		window, err = s.repo.OpsExecutionWindow.Create(ctx, &maintent.OpsExecutionWindow{
			StartAt: param.StartAt,
			EndAt:   param.EndAt,
		})
		return err
	})
	if err != nil {
		return nil, err
	}

	return window, nil
}

func (s *svc) UpdateOpsExecutionWindow(
	ctx context.Context,
	id uint64,
	param cmxapi.UpdateOpsExecutionWindowParam,
) (*maintent.OpsExecutionWindow, error) {
	param, err := param.Normalize()
	if err != nil {
		return nil, errs.APIErrorNew(baseapi.ErrCodeInvalidArgument, err)
	}

	var window *maintent.OpsExecutionWindow
	err = s.dbp.Transaction(ctx, func(ctx context.Context) error {
		window, err = s.repo.OpsExecutionWindow.Update(ctx, &maintent.OpsExecutionWindow{
			ID:      id,
			StartAt: param.StartAt,
			EndAt:   param.EndAt,
		})
		return err
	})
	if err != nil {
		return nil, err
	}

	return window, nil
}

func (s *svc) DeleteOpsExecutionWindow(ctx context.Context, id uint64) error {
	err := s.dbp.Transaction(ctx, func(ctx context.Context) error {
		return s.repo.OpsExecutionWindow.Delete(ctx, id)
	})
	if err != nil {
		return fmt.Errorf("delete ops execution window failed: %w", err)
	}

	return nil
}
