using System.Collections.Concurrent;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using PCL.Core.Utils;
using PCL.Core.IO.Net.Http;

namespace PCL;

public class MyImage : Image
{
    public MyImage()
    {
        Initialized += (_, _) => Load();
        SizeChanged += (_, _) => UpdateClip();
    }

    /// <summary>
    ///     实际被呈现的图片地址。
    /// </summary>
    public string ActualSource
    {
        get => field;
        set
        {
            if (string.IsNullOrEmpty(value))
                value = null;
            if ((field ?? "") == (value ?? ""))
                return;
            field = value;
            Dispatcher.BeginInvoke(new Func<Task>(async () =>
            {
                try
                {
                    ImageSource bitmap = value is null ? null : await Task.Run(() => new MyBitmap(value));
                    base.Source = bitmap;
                }
                catch (Exception ex)
                {
                    ModBase.Log(ex, $"加载图片失败（{value}）");
                    try
                    {
                        if (value.StartsWithF(ModBase.pathTemp) && File.Exists(value)) File.Delete(value);
                    }
                    catch
                    {
                    }
                }
            })); // 在这里先触发可能的文件读取，尽量避免在 UI 线程中读取文件
            // ignored
        }
    }

    private void Load() // 属性读取顺序修正：在完成 XAML 属性读取后再触发图片加载（#4868）
    {
        if (Source is null)
        {
            ActualSource = null;
            return;
        }

        if (!Source.StartsWithF("http"))
        {
            ActualSource = Source;
            return;
        }

        var url = Source;
        var tempPath = GetTempPath(url);
        var tempFile = new FileInfo(tempPath);
        var enableCache = this.EnableCache;
        if (enableCache && tempFile.Exists)
        {
            ActualSource = tempPath;
            if (DateTime.Now - tempFile.LastWriteTime < fileCacheExpiredTime)
                return; // 无需刷新缓存
        }

        Dispatcher.BeginInvoke(new Func<Task>(async () =>
        {
            try
            {
                // 下载
                ActualSource = LoadingSource;

                var resp = await DownloadImageAsync(url);
                if (!string.IsNullOrEmpty(resp))
                {
                    ActualSource = resp;
                    return;
                }

                resp = await DownloadImageAsync(FallbackSource);
                if (!string.IsNullOrEmpty(resp))
                {
                    ActualSource = resp;
                    return;
                }
            }
            catch (Exception ex)
            {
                // 更换备用地址
                ModBase.Log(ex, $"Online image get fail（source = {url}, fallback = {FallbackSource}）", ModBase.LogLevel.Developer);
                tempPath = GetTempPath(url);
                tempFile = new FileInfo(tempPath);
                if (enableCache && tempFile.Exists)
                {
                    ActualSource = tempPath;
                    if (DateTime.Now - tempFile.LastWriteTime < fileCacheExpiredTime)
                        return;
                }
            }
        }));
    }

    public static Task<string> DownloadImageAsync(string url)
    {
        return _downloadTasks.GetOrAdd(url, key =>
        {
            var t = DownloadImageInternalAsync(key);
            t.ContinueWith(_ => _downloadTasks.TryRemove(url, out _));
            return t;
        });
    }

    public static string GetTempPath(string url)
    {
        return Path.Combine(ModBase.pathTemp, "Cache", "Images", $"{ModBase.GetStringMD5(url)}.png");
    }

    private static readonly ConcurrentDictionary<string, Task<string>> _downloadTasks = new();

    private static async Task<string> DownloadImageInternalAsync(string url)
    {
        var tempPath = GetTempPath(url);
        var tempDownloadingPath = tempPath + RandomUtils.NextInt(0, 1000000);

        try
        {
            Directory.CreateDirectory(ModBase.GetPathFromFullPath(tempPath)); // 重新实现下载，以避免携带 Header（#5072）
            using (var fs = new FileStream(tempDownloadingPath, FileMode.Create, FileAccess.ReadWrite, FileShare.Read))
            {
                using (var response = await HttpRequest.Create(url)
                           .SendAsync(addMetedata: false))
                {
                    response.EnsureSuccessStatusCode();

                    using (var nfs = await response.AsStreamAsync())
                    {
                        fs.SetLength(0L);
                        await nfs.CopyToAsync(fs);
                    }
                }
            }

            File.Move(tempDownloadingPath, tempPath, true);
            return tempPath;
        }
        catch (Exception ex)
        {
            if (File.Exists(tempPath)) File.Delete(tempPath);
            if (File.Exists(tempDownloadingPath)) File.Delete(tempDownloadingPath);

            ModBase.Log(ex, $"Try to get online image fail (url = {url}, dest = {tempPath})");
            return string.Empty;
        }
    }

    #region 公开属性

    public TimeSpan fileCacheExpiredTime = TimeSpan.FromDays(14d);

    public bool EnableCache
    {
        get => (bool)GetValue(EnableCacheProperty);
        set => SetValue(EnableCacheProperty, value);
    }

    public new static readonly DependencyProperty EnableCacheProperty =
        DependencyProperty.Register("EnableCache", typeof(bool), typeof(MyImage), new PropertyMetadata(true));

    /// <summary>
    ///     与 Image 的 Source 类似。
    ///     若输入以 http 开头的字符串，则会尝试下载图片然后显示，图片会保存为本地缓存。
    ///     支持 WebP 格式的图片。
    /// </summary>
    public new string Source // 覆写 Image 的 Source 属性
    {
        get => field;
        set
        {
            if (string.IsNullOrEmpty(value))
                value = null;
            if ((field ?? "") == (value ?? ""))
                return;
            field = value;
            if (!IsInitialized)
                return; // 属性读取顺序修正：在完成 XAML 属性读取后再触发图片加载（#4868）
            Load();
        }
    } = "";

    public new static readonly DependencyProperty SourceProperty = DependencyProperty.Register("Source", typeof(string),
        typeof(MyImage), new PropertyMetadata((sender, e) =>
        {
            if (sender is not null) ((MyImage)sender).Source = e.NewValue.ToString();
        }));

    /// <summary>
    ///     当 Source 首次下载失败时，会从该备用地址加载图片。
    /// </summary>
    public string FallbackSource { get; set; }

    /// <summary>
    ///     正在下载网络图片时显示的本地图片。
    /// </summary>
    public string LoadingSource { get; set; } = "pack://application:,,,/images/Icons/NoIcon.png";
    public CornerRadius CornerRadius
    {
        get => (CornerRadius)GetValue(CornerRadiusProperty);
        set => SetValue(CornerRadiusProperty, value);
    }
    private static readonly DependencyProperty CornerRadiusProperty =
        DependencyProperty.Register(
            "CornerRadius",
            typeof(CornerRadius),
            typeof(MyImage),
            new FrameworkPropertyMetadata(
                new CornerRadius(-1),
                OnCornerRadiusChanged)
        );

    private static void OnCornerRadiusChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        ((MyImage)d).UpdateClip();
    }

    private void UpdateClip() // Handles Me.SizeChanged will be added separately
    {
        if (ActualWidth > 0 && ActualHeight > 0 &&
            CornerRadius.TopLeft >= 0 && CornerRadius.TopRight >= 0)
        {
            Clip = new RectangleGeometry(
                new Rect(0, 0, ActualWidth, ActualHeight),
                CornerRadius.TopLeft,
                CornerRadius.TopRight);
        }
    }
    #endregion
}