using ErsatzTV.Core;
using ErsatzTV.Core.Api.ChannelTemplates;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Errors;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Infrastructure.Data;
using ErsatzTV.Infrastructure.Extensions;
using Microsoft.EntityFrameworkCore;

namespace ErsatzTV.Application.ChannelTemplates;

public class UpdateChannelTemplateHandler(
    IDbContextFactory<TvContext> dbContextFactory,
    IConfigElementRepository configElementRepository)
    : IRequestHandler<UpdateChannelTemplate, Either<BaseError, ChannelTemplateResponseModel>>
{
    public async Task<Either<BaseError, ChannelTemplateResponseModel>> Handle(
        UpdateChannelTemplate request,
        CancellationToken cancellationToken)
    {
        await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
        Option<ChannelTemplate> maybeTemplate = await dbContext.ChannelTemplates
            .SelectOneAsync(t => t.Id, t => t.Id == request.ChannelTemplateId, cancellationToken);
        foreach (ChannelTemplate template in maybeTemplate)
        {
            if (template.IsSystem)
            {
                return BaseError.New("System templates cannot be updated.");
            }

            Option<BaseError> maybeError =
                await ChannelTemplateCommandBase.ValidateCommon(
                    dbContext,
                    request,
                    request.ChannelTemplateId,
                    cancellationToken);
            foreach (BaseError error in maybeError)
            {
                return error;
            }

            request.ApplyTo(template);
            await dbContext.SaveChangesAsync(cancellationToken);
            int? defaultTemplateId =
                await ChannelTemplateDefault.GetDefaultTemplateId(configElementRepository, cancellationToken);
            return ChannelTemplateMapper.ProjectToResponseModel(template, defaultTemplateId);
        }

        return new NotFoundError($"ChannelTemplate {request.ChannelTemplateId} does not exist.");
    }
}
