package repo

import (
	"context"
	"fmt"

	auditent "github.com/tidbcloud/devops/entity/audit"
	auditmod "github.com/tidbcloud/devops/models/audit"
	"github.com/tidbcloud/devops/pkg/infra/utils/container"
	"github.com/tidbcloud/devops/pkg/infra/utils/repoopt"
	"github.com/tidbcloud/devops/pkg/service/audit/repo/cvt"
	"github.com/tidbcloud/pkgv2/db"
)

type Driver interface {
	Create(ctx context.Context, adtLog *auditent.AuditLog) error
	Query(ctx context.Context, opts ...repoopt.Option) ([]*auditent.AuditLog, error)
	Count(ctx context.Context, opts ...repoopt.Option) (int64, error)
}

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

func (d *driver) Create(ctx context.Context, adtLog *auditent.AuditLog) error {
	wdb := d.dbProvider.WriteDB(ctx)

	m := d.cvter.EntityToModel().AuditLog(adtLog)
	err := wdb.Create(m).Error
	if err != nil {
		return fmt.Errorf("create %s audit log for obj %s failed: %w", adtLog.Type, adtLog.ObjectID, err)
	}

	return nil
}

func (d *driver) Query(ctx context.Context, opts ...repoopt.Option) ([]*auditent.AuditLog, error) {
	rdb := d.dbProvider.ReadDB(ctx)
	adtLogs := []*auditmod.AuditLog{}

	rdb = rdb.Model(&auditmod.AuditLog{})

	rdb = repoopt.Aggregate(opts...).Apply(rdb)

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

	return container.TransformSlice(adtLogs, d.cvter.ModelToEntity().AuditLog), nil
}

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

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

	return count, nil
}
