using EntKube.Provisioning.Domain;
using EntKube.SharedKernel.Domain;

namespace EntKube.Provisioning.Features.ProvisionService;

/// <summary>
/// Handles requests to provision a new shared service on a cluster. A tenant admin
/// selects a service type (MinIO, CloudNativePG, Keycloak), provides a name and
/// target namespace, and we create the ServiceInstance aggregate. The actual deployment
/// is handled asynchronously by the reconciliation background service.
/// </summary>
public class ProvisionServiceHandler
{
    private readonly IServiceInstanceRepository repository;

    public ProvisionServiceHandler(IServiceInstanceRepository repository)
    {
        this.repository = repository;
    }

    public async Task<Result<Guid>> HandleAsync(ProvisionServiceRequest request, CancellationToken ct = default)
    {
        // Validate the request contains all required fields.

        if (request.ClusterId == Guid.Empty)
        {
            return Result.Failure<Guid>("Cluster ID is required.");
        }

        if (string.IsNullOrWhiteSpace(request.Name))
        {
            return Result.Failure<Guid>("Service name is required.");
        }

        if (string.IsNullOrWhiteSpace(request.Namespace))
        {
            return Result.Failure<Guid>("Namespace is required.");
        }

        // Create the service instance aggregate. The domain enforces any invariants
        // about valid service configurations.

        ServiceInstance instance = ServiceInstance.Provision(
            request.ClusterId,
            request.ServiceType,
            request.Name,
            request.Namespace);

        // Persist it. The background reconciliation loop will pick it up and deploy it.

        await repository.AddAsync(instance, ct);

        return Result.Success(instance.Id);
    }
}

public record ProvisionServiceRequest(
    Guid ClusterId,
    ServiceType ServiceType,
    string Name,
    string Namespace);
