using Microsoft.Extensions.Logging;
using TeleWave.Application.Common.Interfaces;

namespace TeleWave.Infrastructure.Media;

/// <summary>
/// Скачивает изображение по URL через HTTP-клиент «metadata» и определяет расширение.
///
/// Любая неудача — это null, а не исключение: постер не тот повод, чтобы ронять применение
/// метаданных. Но молчать о ней нельзя — снаружи «постера нет» неотличимо от «постера не было
/// в источнике», а причина обычно сетевая: у TMDb картинки лежат на отдельном хосте
/// (<c>image.tmdb.org</c>), и он бывает недоступен там, где сам API работает.
/// </summary>
public sealed class ImageDownloader(IHttpClientFactory httpFactory, ILogger<ImageDownloader> logger)
    : IImageDownloader
{
    public async Task<DownloadedImage?> DownloadAsync(
        string url,
        CancellationToken cancellationToken
    )
    {
        // Пускаем только абсолютные http/https URL: URL приходит из ответа metadata-провайдера
        // (постеры TMDb/OMDb), и скомпрометированный/подменённый ответ не должен заставить сервер
        // дёрнуть file://, ftp:// или иную схему.
        if (
            !Uri.TryCreate(url, UriKind.Absolute, out var uri)
            || (uri.Scheme != Uri.UriSchemeHttp && uri.Scheme != Uri.UriSchemeHttps)
        )
        {
            logger.LogWarning("Картинка не скачана: недопустимый адрес {Url}", url);
            return null;
        }

        try
        {
            var client = httpFactory.CreateClient("metadata");
            using var response = await client.GetAsync(uri, cancellationToken);
            if (!response.IsSuccessStatusCode)
            {
                logger.LogWarning(
                    "Картинка не скачана: {Url} ответил {Status}",
                    url,
                    (int)response.StatusCode
                );
                return null;
            }

            var ext = ExtensionFor(url, response.Content.Headers.ContentType?.MediaType);
            var bytes = await response.Content.ReadAsByteArrayAsync(cancellationToken);
            if (bytes.Length == 0)
            {
                logger.LogWarning("Картинка не скачана: {Url} вернул пустой ответ", url);
                return null;
            }

            return new DownloadedImage(bytes, ext);
        }
        catch (Exception ex)
            when (ex is HttpRequestException or TaskCanceledException or IOException)
        {
            // Самая частая причина — недоступный хост картинок: он отдельный от хоста API.
            logger.LogWarning(ex, "Картинка не скачана: {Url} недоступен", url);
            return null;
        }
    }

    private static string ExtensionFor(string url, string? mediaType) =>
        mediaType switch
        {
            "image/png" => ".png",
            "image/webp" => ".webp",
            "image/gif" => ".gif",
            "image/jpeg" => ".jpg",
            _ => Path.GetExtension(new Uri(url).AbsolutePath) is { Length: > 1 } e
                ? e.ToLowerInvariant()
                : ".jpg",
        };
}
