package repo

import (
	"context"
	"fmt"

	"github.com/tidbcloud/devops/entity"
	rtmod "github.com/tidbcloud/devops/models/remediationticket"
	"github.com/tidbcloud/devops/pkg/infra/utils/container"
	"github.com/tidbcloud/devops/pkg/infra/utils/repoopt"
	"github.com/tidbcloud/devops/pkg/service/remediationticket/repo/cvt"
	"github.com/tidbcloud/pkgv2/db"
	"gorm.io/gorm"
)

type RemediationTicketApprovalDriver interface {
	Save(ctx context.Context, ticket *entity.RemediationTicketPhaseApproval) (*entity.RemediationTicketPhaseApproval, error)
	Load(ctx context.Context, id uint64) (*entity.RemediationTicketPhaseApproval, error)
	Query(ctx context.Context, opts ...repoopt.Option) ([]*entity.RemediationTicketPhaseApproval, error)
	Count(ctx context.Context, opts ...repoopt.Option) (int64, error)
	Patch(ctx context.Context, id uint64, ticket *entity.RemediationTicketPhaseApproval) (*entity.RemediationTicketPhaseApproval, error)
}

type tadriver struct {
	cvter      *cvt.Converter
	dbProvider db.Provider
}

func (d *tadriver) Save(ctx context.Context, ticketApproval *entity.RemediationTicketPhaseApproval) (*entity.RemediationTicketPhaseApproval, error) {
	wdb := d.dbProvider.WriteDB(ctx)
	taMod := d.cvter.EntityToModel().RemediationTicketPhaseApproval(ticketApproval)

	err := wdb.Session(&gorm.Session{FullSaveAssociations: false}).Save(taMod).Error
	if err != nil {
		return nil, fmt.Errorf("save remediation ticket phase approval failed: %w", err)
	}

	// fill back id
	return d.cvter.ModelToEntity().RemediationTicketPhaseApproval(taMod), nil
}

func (d *tadriver) Load(ctx context.Context, id uint64) (*entity.RemediationTicketPhaseApproval, error) {
	rdb := d.dbProvider.ReadDB(ctx)
	taMod := &rtmod.RemediationTicketApprovals{}

	err := rdb.Model(&rtmod.RemediationTicket{}).Where("id = ?", id).First(taMod).Error
	if err != nil {
		return nil, fmt.Errorf("load remediation ticket approval %d failed: %w", id, err)
	}

	return d.cvter.ModelToEntity().RemediationTicketPhaseApproval(taMod), nil
}

func (d *tadriver) Query(ctx context.Context, opts ...repoopt.Option) ([]*entity.RemediationTicketPhaseApproval, error) {
	rdb := d.dbProvider.ReadDB(ctx)
	taMods := make([]*rtmod.RemediationTicketApprovals, 0)

	rdb = rdb.Model(&rtmod.RemediationTicketApprovals{})
	rdb = repoopt.Aggregate(opts...).Apply(rdb)

	err := rdb.Find(&taMods).Error
	if err != nil {
		return nil, fmt.Errorf("query remediation ticket approvals failed: %w", err)
	}

	return container.TransformSlice(taMods, d.cvter.ModelToEntity().RemediationTicketPhaseApproval), nil
}

func (d *tadriver) Count(ctx context.Context, opts ...repoopt.Option) (int64, error) {
	rdb := d.dbProvider.ReadDB(ctx).Model(&rtmod.RemediationTicketApprovals{})
	rdb = repoopt.Aggregate(opts...).Apply(rdb)

	var count int64
	err := rdb.Count(&count).Error
	if err != nil {
		return 0, fmt.Errorf("count remediation ticket approvals failed: %w", err)
	}

	return count, nil
}

func (d *tadriver) Patch(ctx context.Context, id uint64, tapatch *entity.RemediationTicketPhaseApproval) (*entity.RemediationTicketPhaseApproval, error) {
	wdb := d.dbProvider.WriteDB(ctx)
	taMod := d.cvter.EntityToModel().RemediationTicketPhaseApproval(tapatch)

	err := wdb.Session(&gorm.Session{FullSaveAssociations: false}).Model(taMod).Updates(taMod).Error
	if err != nil {
		return nil, fmt.Errorf("patch remediationticket failed: %w", err)
	}

	// fill back id
	return d.cvter.ModelToEntity().RemediationTicketPhaseApproval(taMod), nil
}
