package email

import (
	"context"
	"fmt"

	msgent "github.com/tidbcloud/devops/entity/message"
	msgmod "github.com/tidbcloud/devops/models/message"
	"github.com/tidbcloud/devops/pkg/infra/utils/container"
	"github.com/tidbcloud/devops/pkg/infra/utils/repoopt"
	"github.com/tidbcloud/devops/pkg/service/message/repo/cvt"

	"github.com/tidbcloud/pkgv2/db"
)

type EmailRecordDriver interface {
	Load(ctx context.Context, id uint64) (*msgent.EmailRecord, error)
	Query(ctx context.Context, opts ...repoopt.Option) ([]*msgent.EmailRecord, error)
	Count(ctx context.Context, opts ...repoopt.Option) (int64, error)
	Save(ctx context.Context, item *msgent.EmailRecord) (*msgent.EmailRecord, error)
}

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

func (r *emailRecordD) Load(ctx context.Context, id uint64) (*msgent.EmailRecord, error) {
	rdb := r.dbProvider.ReadDB(ctx)

	mod := &msgmod.EmailRecord{}
	err := rdb.Model(&msgmod.EmailRecord{}).Where("id = ?", id).First(mod).Error
	if err != nil {
		return nil, fmt.Errorf("find email record failed: %w", err)
	}

	return r.cvter.ModelToEntity().EmailRecord(mod), nil
}

func (d *emailRecordD) Query(ctx context.Context, opts ...repoopt.Option) ([]*msgent.EmailRecord, error) {
	rdb := d.dbProvider.ReadDB(ctx)
	mods := make([]*msgmod.EmailRecord, 0)

	rdb = rdb.Model(&msgmod.EmailRecord{})
	rdb = repoopt.Aggregate(opts...).Apply(rdb)

	err := rdb.Find(&mods).Error
	if err != nil {
		return nil, fmt.Errorf("query email records failed: %w", err)
	}

	return container.TransformSlice(mods, d.cvter.ModelToEntity().EmailRecord), nil
}

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

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

	return count, nil
}

func (r *emailRecordD) Save(ctx context.Context, item *msgent.EmailRecord) (*msgent.EmailRecord, error) {
	var err error
	wdb := r.dbProvider.WriteDB(ctx)

	mod := r.cvter.EntityToModel().EmailRecord(item)
	err = wdb.Save(mod).Error
	if err != nil {
		return nil, fmt.Errorf("save email records failed: %w", err)
	}

	return r.cvter.ModelToEntity().EmailRecord(mod), nil
}
