using Microsoft.Web.WebView2.Core;
using System.Collections.Concurrent;
using YMhut.Box.Core.App;
using YMhut.Box.Core.Settings;

namespace YMhut.Box.WinUI.Services;

public sealed class WebView2EnvironmentFactory(
    AppPaths paths,
    ISettingsService settingsService)
{
    private readonly ConcurrentDictionary<string, Lazy<Task<CoreWebView2Environment>>> _environmentCache = new(StringComparer.OrdinalIgnoreCase);

    public async Task<CoreWebView2Environment> CreateAsync(
        string profileName,
        bool? hardwareAccelerationEnabled = null,
        string? userDataFolder = null)
    {
        var resolvedUserDataFolder = string.IsNullOrWhiteSpace(userDataFolder)
            ? GetUserDataFolder(profileName)
            : Path.GetFullPath(userDataFolder);
        var useHardwareAcceleration = hardwareAccelerationEnabled ?? settingsService.Current.HardwareAccelerationEnabled;
        var cacheKey = $"{Path.GetFullPath(resolvedUserDataFolder)}|gpu={useHardwareAcceleration}";
        var lazy = _environmentCache.GetOrAdd(
            cacheKey,
            _ => new Lazy<Task<CoreWebView2Environment>>(
                () => CreateEnvironmentCoreAsync(resolvedUserDataFolder, useHardwareAcceleration),
                LazyThreadSafetyMode.ExecutionAndPublication));

        try
        {
            return await lazy.Value.ConfigureAwait(false);
        }
        catch
        {
            _environmentCache.TryRemove(cacheKey, out _);
            throw;
        }
    }

    public async Task PrewarmAsync(params string[] profileNames)
    {
        var profiles = profileNames
            .Where(profile => !string.IsNullOrWhiteSpace(profile))
            .Distinct(StringComparer.OrdinalIgnoreCase)
            .ToArray();
        if (profiles.Length == 0)
        {
            return;
        }

        await Task.WhenAll(profiles.Select(profile => CreateAsync(profile))).ConfigureAwait(false);
    }

    private static async Task<CoreWebView2Environment> CreateEnvironmentCoreAsync(
        string resolvedUserDataFolder,
        bool useHardwareAcceleration)
    {
        Directory.CreateDirectory(resolvedUserDataFolder);
        var options = new CoreWebView2EnvironmentOptions
        {
            AdditionalBrowserArguments = useHardwareAcceleration ? string.Empty : "--disable-gpu --disable-gpu-compositing"
        };
        return await CoreWebView2Environment.CreateWithOptionsAsync(
            browserExecutableFolder: null,
            userDataFolder: resolvedUserDataFolder,
            options: options);
    }

    public string GetUserDataFolder(string profileName)
    {
        var segments = profileName
            .Split(['\\', '/'], StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
            .Select(SanitizeProfileSegment)
            .Where(segment => !string.IsNullOrWhiteSpace(segment))
            .ToArray();

        if (segments.Length == 0)
        {
            segments = ["Default"];
        }

        return Path.Combine([paths.Cache, "WebView2", .. segments]);
    }

    private static string SanitizeProfileSegment(string profileName)
    {
        var invalid = Path.GetInvalidFileNameChars();
        var value = new string(profileName.Select(character => invalid.Contains(character) ? '_' : character).ToArray());
        return string.IsNullOrWhiteSpace(value) ? "Default" : value;
    }
}
