using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Iptv;

namespace ErsatzTV.Application.Configuration;

public class UpdateIptvSettingsHandler(IConfigElementRepository configElementRepository)
    : IRequestHandler<UpdateIptvSettings, Either<BaseError, Unit>>
{
    public async Task<Either<BaseError, Unit>> Handle(
        UpdateIptvSettings request,
        CancellationToken cancellationToken)
    {
        Validation<BaseError, Unit> validation = Validate(request);
        return await validation.Apply<Unit, Unit>(_ => ApplyUpdate(request.IptvSettings, cancellationToken));
    }

    private async Task<Unit> ApplyUpdate(IptvSettingsViewModel iptvSettings, CancellationToken cancellationToken)
    {
        string baseUrl = (iptvSettings.BaseUrl ?? string.Empty).Trim();

        // A blank value clears the setting so the request-derived behavior is restored.
        if (string.IsNullOrWhiteSpace(baseUrl))
        {
            await configElementRepository.Delete(ConfigElementKey.IptvBaseUrl, cancellationToken);
        }
        else
        {
            await configElementRepository.Upsert(ConfigElementKey.IptvBaseUrl, baseUrl, cancellationToken);
        }

        return Unit.Default;
    }

    private static Validation<BaseError, Unit> Validate(UpdateIptvSettings request)
    {
        string baseUrl = request.IptvSettings.BaseUrl;

        // Blank is valid (clears the override); a non-blank value must be a well-formed advertised base URL.
        if (string.IsNullOrWhiteSpace(baseUrl))
        {
            return Unit.Default;
        }

        return AdvertisedBaseUrl.TryParse(baseUrl)
            .Map(_ => Unit.Default)
            .ToValidation<BaseError>(
                "Advertised base URL must be an absolute http(s) URL with no credentials, query, or fragment");
    }
}
