package password

import (
	"context"
	"errors"

	"github.com/tidbcloud/pkgv2/db"
	"go.opentelemetry.io/otel"
	"gorm.io/gorm"

	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/entity"
	passwordrepo "github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/repository/password"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/infra/repoimpl/schema"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
)

var tracer = otel.Tracer("password_repo_impl")

func NewPasswordRepo(provider db.Provider) passwordrepo.Repo {
	return &passwordRepoImpl{
		provider: provider,
	}
}

type passwordRepoImpl struct {
	provider db.Provider
}

func (r *passwordRepoImpl) SetEncryptedPassword(
	ctx context.Context,
	resourcePoolId uint64,
	clusterId string,
	user entity.ClusterUser,
	encryptedPassword string,
) bizerr.BizError {
	ctx, span := tracer.Start(ctx, "passwordRepo.SetEncryptedPassword")
	defer span.End()

	wdb := r.provider.WriteDB(ctx)

	var existing schema.ClusterPassword
	err := wdb.Where("resource_pool_id = ? AND cluster_id = ? AND user = ?", resourcePoolId, clusterId, string(user)).
		Take(&existing).Error

	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			// Create new record
			record := &schema.ClusterPassword{
				ResourcePoolId:    resourcePoolId,
				ClusterId:         clusterId,
				User:              string(user),
				EncryptedPassword: encryptedPassword,
			}
			if err := wdb.Create(record).Error; err != nil {
				return bizerr.WrapGormError(err, "failed to create cluster password")
			}
			return nil
		}
		return bizerr.WrapGormError(err, "failed to query cluster password")
	}

	// Update existing record
	existing.EncryptedPassword = encryptedPassword
	if err := wdb.Save(&existing).Error; err != nil {
		return bizerr.WrapGormError(err, "failed to update cluster password")
	}
	return nil
}

func (r *passwordRepoImpl) GetEncryptedPassword(
	ctx context.Context,
	resourcePoolId uint64,
	clusterId string,
	user entity.ClusterUser,
) (string, bizerr.BizError) {
	ctx, span := tracer.Start(ctx, "passwordRepo.GetEncryptedPassword")
	defer span.End()

	rdb := r.provider.ReadDB(ctx)

	var record schema.ClusterPassword
	err := rdb.Where("resource_pool_id = ? AND cluster_id = ? AND user = ?", resourcePoolId, clusterId, string(user)).
		Take(&record).Error

	if err != nil {
		return "", bizerr.WrapGormError(err, "failed to get cluster password")
	}

	return record.EncryptedPassword, nil
}

func (r *passwordRepoImpl) DeleteEncryptedPassword(
	ctx context.Context,
	resourcePoolId uint64,
	clusterId string,
	user entity.ClusterUser,
) bizerr.BizError {
	ctx, span := tracer.Start(ctx, "passwordRepo.DeleteEncryptedPassword")
	defer span.End()

	wdb := r.provider.WriteDB(ctx)

	result := wdb.Where("resource_pool_id = ? AND cluster_id = ? AND user = ?", resourcePoolId, clusterId, string(user)).
		Delete(&schema.ClusterPassword{})

	if result.Error != nil {
		return bizerr.WrapGormError(result.Error, "failed to delete cluster password")
	}

	return nil
}
