using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Modules.Library.WebApi.Models.Anime;
using Modules.Library.WebApi.Models.Anime.CommonProperties;
using Modules.Library.WebApi.Models.Views.Anime;
using System.Net;

namespace Modules.Library.WebApi.Controllers;

[ApiController]
[ApiExplorerSettings(GroupName = "AnimeTitleV1")]
[Route("MediaContent/Anime/Title")]
//[Route("[controller]")]
[Authorize]
public class AnimeTitleController(IMediator mediator) : ControllerBase
{
    [HttpGet("List")]
    [AllowAnonymous]
    public async Task<IEnumerable<TitleShort>> List()
    {
        var titles = await mediator.Send(new Application.Queries.Anime.AnimeTitle.AnimeTitleListQuery());

        return titles.Select(q => new TitleShort
        {
            Id = q.Id,

            Rate = q.Rate,
            MyRate = q.MyRate,

            ViewsCount = 0,
            MyViewsCount = 0,

            Names = q.CommonProperties.Names.Select(GetNameItem),
            Preview = q.CommonProperties.Preview != null ? GetMediaInfo(q.CommonProperties.Preview) : null,

            Genres = q.CommonProperties.Genres.Select(GetGenreProportion),

            EstimatedReleaseDate = q.CommonProperties.EstimatedReleaseDate,
            ReleaseDate = q.CommonProperties.ReleaseDate,

            SeasonsCount = Convert.ToUInt32(q.Items.OfType<Application.Models.Anime.Season>().Count()),
            EpisodesCount = Convert.ToUInt32(q.Items.OfType<Application.Models.Anime.Episode>().Count()),
            EpisodesInsideSeasonsCount = Convert.ToUInt32(q.Items.OfType<Application.Models.Anime.Season>()
                .SelectMany(season => season.Episodes).Count()),

            Completed = q.Completed,
        });
    }

    [HttpGet("Detail")]
    [AllowAnonymous]
    public async Task<TitleDetail> Detail(Guid titleId)
    {
        var title = await mediator.Send(new Application.Queries.Anime.AnimeTitle.AnimeTitleQuery { Id = titleId });
        return new TitleDetail
        {
            Id = title.Id,
            Deleted = title.Deleted,
            CommonProperties = GetCommonProperties(title.CommonProperties),
            Rate = title.Rate,
            MyRate = title.MyRate,
            ViewsCount = 0,
            MyViewsCount = 0,
            Items = title.Items.Select(GetAnimeItem),

            SeasonsCount = Convert.ToUInt32(title.Items.OfType<Application.Models.Anime.Season>().Count()),
            EpisodesCount = Convert.ToUInt32(title.Items.OfType<Application.Models.Anime.Episode>().Count()),
            EpisodesInsideSeasonsCount = Convert.ToUInt32(title.Items.OfType<Application.Models.Anime.Season>().SelectMany(q => q.Episodes).Count()),

            Completed = title.Completed,
        };
    }

    [HttpGet]
    [AllowAnonymous]
    public async Task<Title> ById(Guid titleId)
    {
        var title = await mediator.Send(new Application.Queries.Anime.AnimeTitle.AnimeTitleQuery { Id = titleId });
        return new Title
        {
            Id = title.Id,
            Deleted = title.Deleted,
            CommonProperties = GetCommonProperties(title.CommonProperties),
            ContainRates = title.Rate > 0,
            ContainViews = false,
            Items = title.Items.Select(GetAnimeItem),
            Completed = title.Completed,
            ExpirationTimeTicks = title.ExpirationTime.Ticks,
        };
    }

    private static Models.Views.CommonProperties GetCommonProperties(Application.Models.CommonProperties commonProperties)
    {
        return new Models.Views.CommonProperties
        {
            Names = commonProperties.Names.Select(GetNameItem),
            Preview = commonProperties.Preview != null ? GetMediaInfo(commonProperties.Preview) : null,
            Descriptions = commonProperties.Descriptions.Select(q => new Models.Views.Description
            {
                Language = GetLanguage(q.Language),
                Value = q.Value,
                IsOriginal = q.IsOriginal,
            }),
            Genres = commonProperties.Genres.Select(GetGenreProportion),
            RelatedContent = commonProperties.RelatedContent.Select(GetMediaInfo),
            AnnouncementDate = commonProperties.AnnouncementDate,
            EstimatedReleaseDate = commonProperties.EstimatedReleaseDate,
            ReleaseDate = commonProperties.ReleaseDate,
        };
    }
    private static Models.Views.NameItem GetNameItem(Application.Models.NameItem nameItem)
    {
        return new Models.Views.NameItem
        {
            Type = (Models.NameType)nameItem.Type,
            Language = GetLanguage(nameItem.Language),
            Value = nameItem.Value,
        };
    }
    private static Models.Views.GenreProportion GetGenreProportion(Application.Models.GenreProportion genreProportion)
    {
        return new Models.Views.GenreProportion
        {
            Genre = new Models.Views.Dictionary.Genre
            {
                Id = genreProportion.Genre.Id,
                Name = genreProportion.Genre.Name,
                Deleted = genreProportion.Genre.Deleted,
            },
            Proportion = genreProportion.Proportion,
        };
    }
    private static Models.Views.Dictionary.Language GetLanguage(Application.Models.Language language)
    {
        return new Models.Views.Dictionary.Language
        {
            Id = language.Id,
            Name = language.Name,
            CodeIso3 = language.CodeIso3,
            Deleted = language.Deleted,
            IconId = language.IconId,
        };
    }
    private static Models.MediaInfo GetMediaInfo(Application.Models.MediaInfo mediaInfo)
    {
        return new Models.MediaInfo
        {
            Type = (Models.MediaInfoType)mediaInfo.Type,
            ContentType = mediaInfo.ContentType,
            ObjectId = mediaInfo.ObjectId,
        };
    }
    private static AnimeItem GetAnimeItem(Application.Models.Anime.AnimeItem item)
    {
        return item switch
        {
            Application.Models.Anime.Season season => new Season
            {
                Id = season.Id,
                Deleted = season.Deleted,
                Completed = season.Completed,
                CommonProperties = GetCommonProperties(season.CommonProperties),
                Number = season.Number,
                Order = season.Order,
                ExpirationTimeTicks = season.ExpirationTime.Ticks,
                Director = season.Director,
                OriginCountry = season.OriginCountry,
                Episodes = season.Episodes.Select(GetAnimeItem).OfType<Episode>(),
            },
            Application.Models.Anime.Episode episode => new Episode
            {
                Id = episode.Id,
                Deleted = episode.Deleted,
                Completed = episode.Completed,
                CommonProperties = GetCommonProperties(episode.CommonProperties),
                Number = episode.Number,
                Order = episode.Order,
                ExpirationTimeTicks = episode.ExpirationTime.Ticks,
                Variant = episode.Variant,
                Type = (Models.AnimeEpisodeType)episode.Type,
                DurationTicks = episode.Duration?.Ticks,
                DurationType = (Models.AnimeItemSingleDurationType)episode.DurationType,
            },
            _ => throw new NotImplementedException()
        };
    }

    [HttpPost("Vote")]
    public async Task Vote(VoteEdit model) =>
        await mediator.Send(new Application.Commands.Anime.Title.VoteTitleCommand
        {
            TitleId = model.AnimeTitleId ?? throw new ArgumentNullException(nameof(model.AnimeTitleId)),
            RatingPercentage = model.RatingPercentage ?? throw new ArgumentNullException(nameof(model.RatingPercentage)),
        });
    
    [HttpPost("Unvote")]
    public async Task Unvote([FromBody]VoteEdit model) =>
        await mediator.Send(new Application.Commands.Anime.Title.UnvoteTitleCommand
        {
            TitleId = model.AnimeTitleId ?? throw new ArgumentNullException(nameof(model.AnimeTitleId)),
        });

    [HttpPost("Create")]
    public async Task<Guid> CreateTitle([FromForm] TitleCreate model)
    {
        var streams = new List<Stream>();
        try
        {
            var command = new Application.Commands.Anime.Title.CreateAnimeTitleCommand
            {
                Names = model.Names.Select(q => new Application.Commands.Anime.Title.Name
                {
                    LanguageId = q.LanguageId,
                    NameType = (Application.Commands.CommonModels.NameType)q.Type,
                    Value = q.Value,
                }),
                Descriptions = model.Descriptions.Select(q => new Application.Commands.Anime.Title.Description
                {
                    LanguageId = q.LanguageId,
                    IsOriginal = q.IsOriginal,
                    Value = q.Value,
                }),
                Genres = model.Genres.Select(q => new Application.Commands.Anime.Title.Genre
                {
                    GenreId = q.GenreId,
                    Proportion = q.Proportion,
                }),

                AnnouncementDate = model.AnnouncementDate,
                EstimatedReleaseDate = model.EstimatedReleaseDate,
            };
            if (model.Preview?.NewFile != null)
            {
                var stream = model.Preview.NewFile.OpenReadStream();
                streams.Add(stream);
                command.Preview = model.Preview == null ? null : new Application.Commands.Anime.Title.MediaInfo
                {
                    Data = stream,
                    Type = (Application.Commands.CommonModels.MediaInfoType)(model.Preview.NewType ?? throw new Exception("Type is not set")),
                    ContentType = model.Preview.NewFile.ContentType,
                };
            }
            else
            {
                if (!string.IsNullOrWhiteSpace(model.Preview?.NewUrl))
                {
                    command.Preview = new Application.Commands.Anime.Title.MediaInfo
                    {
                        Url = model.Preview.NewUrl,
                        Type = (Application.Commands.CommonModels.MediaInfoType)(model.Preview.NewType ?? throw new Exception("Type is not set")),
                    };
                }
            }
            foreach (var relatedContent in model.RelatedContent)
            {
                if (relatedContent.NewFile != null)
                {
                    var stream = relatedContent.NewFile.OpenReadStream();
                    streams.Add(stream);
                    command.RelatedContent.Add(new Application.Commands.Anime.Title.MediaInfo
                    {
                        Data = stream,
                        Type = (Application.Commands.CommonModels.MediaInfoType)(relatedContent.NewType ?? throw new Exception("Type is not set")),
                        ContentType = relatedContent.NewFile.ContentType,
                    });
                }
                else
                {
                    if (!string.IsNullOrWhiteSpace(relatedContent.NewUrl))
                    {
                        command.RelatedContent.Add(new Application.Commands.Anime.Title.MediaInfo
                        {
                            Url = relatedContent.NewUrl,
                            Type = (Application.Commands.CommonModels.MediaInfoType)(relatedContent.NewType ?? throw new Exception("Type is not set")),
                        });
                    }
                }
            }
            return await mediator.Send(command);
        }
        finally
        {
            foreach (var stream in streams)
            {
                stream.Close();
            }
        }
    }

    [HttpPost("AddSeason")]
    public async Task<Guid> AddSeason([FromForm] SeasonCreate model)
    {
        var streams = new List<Stream>();
        try
        {
            var command = new Application.Commands.Anime.Title.AddSeasonCommand
            {
                TitleId = model.AnimeTitleId,
                Names = model.Names.Select(q => new Application.Commands.Anime.Title.Name
                {
                    LanguageId = q.LanguageId,
                    NameType = (Application.Commands.CommonModels.NameType)q.Type,
                    Value = q.Value,
                }),
                Descriptions = model.Descriptions.Select(q => new Application.Commands.Anime.Title.Description
                {
                    LanguageId = q.LanguageId,
                    IsOriginal = q.IsOriginal,
                    Value = q.Value,
                }),
                Genres = model.Genres.Select(q => new Application.Commands.Anime.Title.Genre
                {
                    GenreId = q.GenreId,
                    Proportion = q.Proportion,
                }),

                AnnouncementDate = model.AnnouncementDate,
                EstimatedReleaseDate = model.EstimatedReleaseDate,

                Number = model.Number,
            };
            if (model.Preview?.NewFile != null)
            {
                var stream = model.Preview.NewFile.OpenReadStream();
                streams.Add(stream);
                command.Preview = model.Preview == null ? null : new Application.Commands.Anime.Title.MediaInfo
                {
                    Data = stream,
                    Type = (Application.Commands.CommonModels.MediaInfoType)(model.Preview.NewType ?? throw new Exception("Type is not set")),
                    ContentType = model.Preview.NewFile.ContentType,
                };
            }
            else
            {
                if (!string.IsNullOrWhiteSpace(model.Preview?.NewUrl))
                {
                    command.Preview = new Application.Commands.Anime.Title.MediaInfo
                    {
                        Url = model.Preview.NewUrl,
                        Type = (Application.Commands.CommonModels.MediaInfoType)(model.Preview.NewType ?? throw new Exception("Type is not set")),
                    };
                }
            }
            foreach (var relatedContent in model.RelatedContent)
            {
                if (relatedContent.NewFile != null)
                {
                    var stream = relatedContent.NewFile.OpenReadStream();
                    streams.Add(stream);
                    command.RelatedContent.Add(new Application.Commands.Anime.Title.MediaInfo
                    {
                        Data = stream,
                        Type = (Application.Commands.CommonModels.MediaInfoType)(relatedContent.NewType ?? throw new Exception("Type is not set")),
                        ContentType = relatedContent.NewFile.ContentType,
                    });
                }
                else
                {
                    if (!string.IsNullOrWhiteSpace(relatedContent.NewUrl))
                    {
                        command.RelatedContent.Add(new Application.Commands.Anime.Title.MediaInfo
                        {
                            Url = relatedContent.NewUrl,
                            Type = (Application.Commands.CommonModels.MediaInfoType)(relatedContent.NewType ?? throw new Exception("Type is not set")),
                        });
                    }
                }
            }
            return await mediator.Send(command);
        }
        finally
        {
            foreach (var stream in streams)
            {
                stream.Close();
            }
        }
    }

    [HttpPost("DeleteSeason")]
    public async Task DeleteSeason([FromBody] SeasonDelete model)
    {
        await mediator.Send(new Application.Commands.Anime.Title.DeleteSeasonCommand
        {
            TitleId = model.AnimeTitleId,
            SeasonId = model.AnimeSeasonId,
            DisableSoftDelete = true,
        });
    }

    [HttpPost("AddEpisode")]
    public async Task<Guid> AddEpisode([FromForm] EpisodeCreate model)
    {
        var streams = new List<Stream>();
        try
        {
            var command = new Application.Commands.Anime.Title.AddEpisodeCommand
            {
                Type = (Application.Commands.Anime.Models.AnimeEpisodeType)model.Type,
                TitleId = model.AnimeTitleId,
                Names = model.Names.Select(q => new Application.Commands.Anime.Title.Name
                {
                    LanguageId = q.LanguageId,
                    NameType = (Application.Commands.CommonModels.NameType)q.Type,
                    Value = q.Value,
                }),
                Descriptions = model.Descriptions.Select(q => new Application.Commands.Anime.Title.Description
                {
                    LanguageId = q.LanguageId,
                    IsOriginal = q.IsOriginal,
                    Value = q.Value,
                }),
                Genres = model.Genres.Select(q => new Application.Commands.Anime.Title.Genre
                {
                    GenreId = q.GenreId,
                    Proportion = q.Proportion,
                }),

                AnnouncementDate = model.AnnouncementDate,
                EstimatedReleaseDate = model.EstimatedReleaseDate,
                ReleaseDate = model.ReleaseDate,

                Number = model.Number,
                
                Duration = model.DurationTicks.HasValue ? TimeSpan.FromTicks(model.DurationTicks.Value) : null,
            };
            if (model.Preview?.NewFile != null)
            {
                var stream = model.Preview.NewFile.OpenReadStream();
                streams.Add(stream);
                command.Preview = model.Preview == null ? null : new Application.Commands.Anime.Title.MediaInfo
                {
                    Data = stream,
                    Type = (Application.Commands.CommonModels.MediaInfoType)(model.Preview.NewType ?? throw new Exception("Type is not set")),
                    ContentType = model.Preview.NewFile.ContentType,
                };
            }
            else
            {
                if (!string.IsNullOrWhiteSpace(model.Preview?.NewUrl))
                {
                    command.Preview = new Application.Commands.Anime.Title.MediaInfo
                    {
                        Url = model.Preview.NewUrl,
                        Type = (Application.Commands.CommonModels.MediaInfoType)(model.Preview.NewType ?? throw new Exception("Type is not set")),
                    };
                }
            }
            foreach (var relatedContent in model.RelatedContent)
            {
                if (relatedContent.NewFile != null)
                {
                    var stream = relatedContent.NewFile.OpenReadStream();
                    streams.Add(stream);
                    command.RelatedContent.Add(new Application.Commands.Anime.Title.MediaInfo
                    {
                        Data = stream,
                        Type = (Application.Commands.CommonModels.MediaInfoType)(relatedContent.NewType ?? throw new Exception("Type is not set")),
                        ContentType = relatedContent.NewFile.ContentType,
                    });
                }
                else
                {
                    if (!string.IsNullOrWhiteSpace(relatedContent.NewUrl))
                    {
                        command.RelatedContent.Add(new Application.Commands.Anime.Title.MediaInfo
                        {
                            Url = relatedContent.NewUrl,
                            Type = (Application.Commands.CommonModels.MediaInfoType)(relatedContent.NewType ?? throw new Exception("Type is not set")),
                        });
                    }
                }
            }
            return await mediator.Send(command);
        }
        finally
        {
            foreach (var stream in streams)
            {
                stream.Close();
            }
        }
    }

    [HttpPost("DeleteEpisode")]
    public async Task DeleteEpisode(EpisodeDelete model) =>
        await mediator.Send(new Application.Commands.Anime.Title.DeleteEpisodeCommand
        {
            TitleId = model.AnimeTitleId,
            EpisodeId = model.AnimeEpisodeId,
            DisableSoftDelete = true,
        });


    [HttpPost("AddName")]
    public async Task AddName(NameEdit model) =>
        await mediator.Send(new Application.Commands.Anime.Title.Properties.Name.AddNameCommand
        {
            TitleId = model.AnimeTitleId ?? throw new ArgumentNullException(nameof(model.AnimeTitleId)),
            LanguageId = model.LanguageId,
            NameType = (Application.Commands.CommonModels.NameType)model.Type,
            Value = model.Value
        });

    [HttpPost("EditName")]
    public async Task EditName(NameEdit model) =>
        await mediator.Send(new Application.Commands.Anime.Title.Properties.Name.EditNameCommand
        {
            TitleId = model.AnimeTitleId ?? throw new ArgumentNullException(nameof(model.AnimeTitleId)),
            LanguageId = model.LanguageId,
            NameType = (Application.Commands.CommonModels.NameType)model.Type,
            Value = model.Value,
            NewLanguageId = model.NewLanguageId,
            NewValue = model.NewValue,
        });

    [HttpPost("DeleteName")]
    public async Task DeleteName(NameEdit model) =>
        await mediator.Send(new Application.Commands.Anime.Title.Properties.Name.DeleteNameCommand
        {
            TitleId = model.AnimeTitleId ?? throw new ArgumentNullException(nameof(model.AnimeTitleId)),
            LanguageId = model.LanguageId,
            NameType = (Application.Commands.CommonModels.NameType)model.Type,
            Value = model.Value,
        });


    [HttpGet("GetMedia")]
    [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(FileStreamResult))]
    [AllowAnonymous]
    public async Task<IActionResult> GetMedia(string objectId) //title id
    {
        if (!string.IsNullOrEmpty(objectId))
        {
            var media = await mediator.Send(new Application.Queries.Anime.GetMediaQuery
            {
                ObjectId = objectId,
            });
            if (media == null)
            {
                return NotFound();
            }
            else
            {
                return new FileStreamResult(media.Data, media.ContentType);
            }
        }
        else
        {
            return NotFound();
        }
    }

    [HttpPost("SetPreview")]
    public async Task SetPreview([FromForm] MediaInfoEdit model)
    {
        if (model.NewFile == null && string.IsNullOrWhiteSpace(model.NewUrl))  throw new Exception("No file or url");
        var command = new Application.Commands.Anime.Title.Properties.Preview.SetPreviewCommand
        {
            TitleId = model.AnimeTitleId ?? throw new ArgumentNullException(nameof(model.AnimeTitleId)),
            Type = (Application.Commands.CommonModels.MediaInfoType)(model.NewType ?? throw new Exception("Type is not set")),
        };
        if (model.NewFile != null)
        {
            await using var stream = model.NewFile.OpenReadStream();
            command.Data = stream;
            command.ContentType = model.NewFile.ContentType;
            // var cd = model.NewFile.ContentDisposition;
            // var a = model.NewFile.FileName;
            await mediator.Send(command);
        }
        else
        {
            if (!string.IsNullOrWhiteSpace(model.NewUrl))
            {
                command.Url = model.NewUrl;
                await mediator.Send(command);
            }
        }
    }

    [HttpPost("ClearPreview")]
    public async Task ClearPreview(MediaInfoEdit model) =>
        await mediator.Send(new Application.Commands.Anime.Title.Properties.Preview.DeletePreviewCommand
        {
            TitleId = model.AnimeTitleId ?? throw new ArgumentNullException(nameof(model.AnimeTitleId)),
        });


    [HttpPost("AddDescription")]
    public async Task AddDescription(DescriptionEdit model) =>
        await mediator.Send(new Application.Commands.Anime.Title.Properties.Description.AddDescriptionCommand
        {
            TitleId = model.AnimeTitleId ?? throw new ArgumentNullException(nameof(model.AnimeTitleId)),
            IsOriginal = model.IsOriginal,
            LanguageId = model.LanguageId,
            Value = model.Value,
        });

    [HttpPost("EditDescription")]
    public async Task EditDescription(DescriptionEdit model) =>
        await mediator.Send(new Application.Commands.Anime.Title.Properties.Description.EditDescriptionCommand
        {
            TitleId = model.AnimeTitleId ?? throw new ArgumentNullException(nameof(model.AnimeTitleId)),
            LanguageId = model.LanguageId,
            IsOriginal = model.IsOriginal,
            Value = model.Value,
            NewLanguageId = model.NewLanguageId,
            NewValue = model.NewValue,
        });

    [HttpPost("DeleteDescription")]
    public async Task DeleteDescription(DescriptionEdit model) =>
        await mediator.Send(new Application.Commands.Anime.Title.Properties.Description.DeleteDescriptionCommand
        {
            TitleId = model.AnimeTitleId ?? throw new ArgumentNullException(nameof(model.AnimeTitleId)),
            LanguageId = model.LanguageId,
            IsOriginal = model.IsOriginal,
            Value = model.Value,
        });


    [HttpPost("AddGenre")]
    public async Task AddDescription(GenreProportionEdit model) =>
        await mediator.Send(new Application.Commands.Anime.Title.Properties.Genre.AddGenreCommand
        {
            TitleId = model.AnimeTitleId ?? throw new ArgumentNullException(nameof(model.AnimeTitleId)),
            GenreId = model.GenreId,
            Proportion = model.Proportion,
        });

    [HttpPost("EditGenre")]
    public async Task EditGenre(GenreProportionEdit model) =>
        await mediator.Send(new Application.Commands.Anime.Title.Properties.Genre.SetGenreProportionCommand
        {
            TitleId = model.AnimeTitleId ?? throw new ArgumentNullException(nameof(model.AnimeTitleId)),
            GenreId = model.GenreId,
            Proportion = model.Proportion
        });

    [HttpPost("DeleteGenre")]
    public async Task DeleteGenre(GenreProportionEdit model) =>
        await mediator.Send(new Application.Commands.Anime.Title.Properties.Genre.DeleteGenreCommand
        {
            TitleId = model.AnimeTitleId ?? throw new ArgumentNullException(nameof(model.AnimeTitleId)),
            GenreId = model.GenreId,
        });

    //[HttpGet("GetRelatedContent")]
    //public async Task AddRelatedContent(IFormFile file, MediaInfoEdit model)
    //{
    //    using var stream = file.OpenReadStream();
    //    await _mediator.Send(new Application.Commands.Anime.Title.Properties.RelatedContent.AddRelatedContentCommand
    //    {
    //        TitleId = model.AnimeTitleId ?? throw new ArgumentNullException(nameof(model.AnimeTitleId)),
    //        Type = (Application.Commands.CommonModels.MediaInfoType)model.Type,
    //        Data = stream,
    //        ContentType = model.ContentType,
    //    });
    //}

    [HttpPost("AddRelatedContent")]
    public async Task AddRelatedContent(IFormFile file, MediaInfoEdit model)
    {
        var command = new Application.Commands.Anime.Title.Properties.RelatedContent.AddRelatedContentCommand
        {
            TitleId = model.AnimeTitleId ?? throw new ArgumentNullException(nameof(model.AnimeTitleId)),
            Type = (Application.Commands.CommonModels.MediaInfoType)(model.NewType ?? throw new Exception("Type is not set")),
        };
        if (model.NewFile != null)
        {
            await using var stream = file.OpenReadStream();
            command.Data = stream;
            command.ContentType = file.ContentType;
            await mediator.Send(command);
        }
        else
        {
            if (!string.IsNullOrWhiteSpace(model.NewUrl))
            {
                command.Url = model.NewUrl;
                await mediator.Send(command);
            }
        }
    }

    [HttpPost("EditRelatedContent")]
    public async Task EditRelatedContent(IFormFile file, MediaInfoEdit model)
    {
        var command = new Application.Commands.Anime.Title.Properties.RelatedContent.EditRelatedContentCommand
        {
            TitleId = model.AnimeTitleId ?? throw new ArgumentNullException(nameof(model.AnimeTitleId)),
            ObjectId = model.ObjectId ?? throw new Exception("Object id is required"),
            NewType = (Application.Commands.CommonModels.MediaInfoType?)model.NewType,
        };
        if (model.NewFile != null)
        {
            await using var stream = file.OpenReadStream();
            command.NewData = stream;
            command.NewContentType = file.ContentType;
            // var cd = file.ContentDisposition;
            // var a = file.FileName;
            await mediator.Send(command);
        }
        else
        {
            if (!string.IsNullOrWhiteSpace(model.NewUrl))
            {
                command.NewUrl = model.NewUrl;
                await mediator.Send(command);
            }
        }
    }

    [HttpPost("DeleteRelatedContent")]
    public async Task DeleteRelatedContent(MediaInfoEdit model) =>
        await mediator.Send(new Application.Commands.Anime.Title.Properties.RelatedContent.DeleteRelatedContentCommand
        {
            TitleId = model.AnimeTitleId ?? throw new ArgumentNullException(nameof(model.AnimeTitleId)),
            ObjectId = model.ObjectId ?? throw new Exception("Object id is required"),
        });


    [HttpPost("SetCompleted")]
    public async Task SetCompleted([FromQuery] Guid titleId, [FromQuery] bool completed) =>
        await mediator.Send(new Application.Commands.Anime.Title.Properties.SetCompletedCommand
        {
            TitleId = titleId,
            Value = completed,
        });

    [HttpPost("SetExpirationTime")]
    public async Task SetExpirationTime([FromQuery] Guid titleId, [FromQuery] long expirationTimeTicks) =>
        await mediator.Send(new Application.Commands.Anime.Title.Properties.SetExpirationTimeCommand
        {
            TitleId = titleId,
            ExpirationTime = TimeSpan.FromTicks(expirationTimeTicks),
        });

    [HttpPost("SetAnnouncementDate")]
    public async Task SetAnnouncementDate(DateEdit model) =>
        await mediator.Send(new Application.Commands.Anime.Title.Properties.SetAnnouncementDateCommand
        {
            TitleId = model.AnimeTitleId ?? throw new ArgumentNullException(nameof(model.AnimeTitleId)),
            Value = model.Value.HasValue ? new DateTimeOffset(model.Value.Value.DateTime, TimeSpan.Zero) : null
        });

    [HttpPost("SetEstimatedReleaseDate")]
    public async Task SetEstimatedReleaseDate(DateEdit model) =>
        await mediator.Send(new Application.Commands.Anime.Title.Properties.SetEstimatedReleaseDateCommand
        {
            TitleId = model.AnimeTitleId ?? throw new ArgumentNullException(nameof(model.AnimeTitleId)),
            Value = model.Value.HasValue ? new DateTimeOffset(model.Value.Value.DateTime, TimeSpan.Zero) : null
        });

    [HttpPost("SetReleaseDate")]
    public async Task SetReleaseDate(DateEdit model) =>
        await mediator.Send(new Application.Commands.Anime.Title.Properties.SetReleaseDateCommand
        {
            TitleId = model.AnimeTitleId ?? throw new ArgumentNullException(nameof(model.AnimeTitleId)),
            Value = model.Value.HasValue ? new DateTimeOffset(model.Value.Value.DateTime, TimeSpan.Zero) : null,
        });
}