package logredactionpolicy

import (
	"context"
	"errors"

	"github.com/tidbcloud/pkgv2/db"
	"gorm.io/gorm"

	globalngv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/nextgen/v1"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/repository/logredactionpolicy"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/infra/repoimpl/schema"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
)

type RepoImpl struct {
	provider db.Provider
}

func NewLogRedactionPolicyRepo(provider db.Provider) logredactionpolicy.Repo {
	return &RepoImpl{
		provider: provider,
	}
}

func (r *RepoImpl) GetByClusterID(
	ctx context.Context,
	clusterID uint64,
) (*globalngv1.LogRedactionPolicy, bizerr.BizError) {
	rdb := r.provider.ReadDB(ctx)
	var configModel schema.LogRedactionPolicy
	if err := rdb.Where("cluster_id = ?", clusterID).First(&configModel).Error; err != nil {
		return nil, bizerr.WrapGormError(err, "fail to get log redaction policy for cluster id %d", clusterID)
	}
	return logRedactionPolicyModelToEn(&configModel), nil
}

func (r *RepoImpl) Upsert(
	ctx context.Context,
	policy *globalngv1.LogRedactionPolicy,
) bizerr.BizError {
	rdb := r.provider.WriteDB(ctx)
	model := logRedactionPolicyEnToModel(policy)
	if err := rdb.Transaction(func(tx *gorm.DB) error {
		var existing schema.LogRedactionPolicy
		// Use Unscoped to find both active and soft-deleted records.
		err := tx.Unscoped().Where("cluster_id = ?", policy.ClusterId).First(&existing).Error
		if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
			// An unexpected error occurred.
			return err
		}
		if errors.Is(err, gorm.ErrRecordNotFound) { // Record does not exist, create a new one.
			return tx.Create(model).Error
		}
		// Record exists, update it.
		model.ID = existing.ID
		// Restore soft-deleted record by resetting DeletedAt.
		model.DeletedAt = gorm.DeletedAt{}
		return tx.Model(&existing).
			Select("*").
			Omit("created_at").
			Updates(model).Error
	}); err != nil {
		return bizerr.WrapGormError(err, "upsert log redaction policy")
	}
	return nil
}

func (r *RepoImpl) DeleteByClusterID(ctx context.Context, clusterID uint64) bizerr.BizError {
	rdb := r.provider.WriteDB(ctx)
	if err := rdb.Model(&schema.LogRedactionPolicy{}).Where("cluster_id = ?", clusterID).Delete(&schema.LogRedactionPolicy{}).Error; err != nil {
		return bizerr.WrapGormError(err, "delete log redaction policy by cluster id")
	}
	return nil
}
