using System.Runtime.InteropServices;
using Windows.ApplicationModel;
using YMhut.Box.Core.App;

namespace YMhut.Box.WinUI.Services;

internal static class RuntimeLayoutBootstrapper
{
    public static bool TryRelaunchFromWritableLayoutIfNeeded()
    {
        try
        {
            CleanupLegacyPersistentRuntime();
            if (IsPackaged() || !RequiresLegacyCompressedLayout(AppContext.BaseDirectory))
            {
                return false;
            }

            const string title = "YMhut Box 启动失败";
            var message =
                "检测到旧版压缩语言资源布局，YMhut Box 不再把运行时复制到用户目录。\n\n" +
                "请使用新版安装包覆盖安装。安装引导程序会清理旧布局并重新铺设程序文件。\n\n" +
                "This installation still uses the legacy compressed language layout. YMhut Box no longer creates a persistent runtime copy under LocalAppData. Please reinstall with the latest setup package.";
            CrashLog.Write(message);
            ShowStartupError(title, message);
            return true;
        }
        catch (Exception exception)
        {
            CrashLog.Write(exception);
            return false;
        }
    }

    public static string InstalledExecutablePath => InstallLayoutPaths.ResolveInstalledExecutablePath();

    public static string InstalledWorkingDirectory => Path.GetDirectoryName(InstalledExecutablePath) ?? AppContext.BaseDirectory;

    private static bool RequiresLegacyCompressedLayout(string directory)
    {
        var legacyLangRoot = Path.Combine(directory, "resources", "lang");
        return Directory.Exists(legacyLangRoot) &&
            Directory.EnumerateFiles(legacyLangRoot, "*.bin", SearchOption.TopDirectoryOnly).Any() &&
            !HasPureLangSatelliteResources(directory);
    }

    private static bool HasPureLangSatelliteResources(string directory)
    {
        var langRoot = Path.Combine(directory, "lang");
        if (!Directory.Exists(langRoot))
        {
            return false;
        }

        foreach (var culture in new[] { "zh-CN", "en-US" })
        {
            var cultureRoot = Path.Combine(langRoot, culture);
            if (!Directory.Exists(cultureRoot))
            {
                return false;
            }

            if (!Directory.EnumerateFiles(cultureRoot, "*.mui", SearchOption.AllDirectories).Any() &&
                !Directory.EnumerateFiles(cultureRoot, "*.resources.dll", SearchOption.AllDirectories).Any())
            {
                return false;
            }
        }

        return true;
    }

    private static void CleanupLegacyPersistentRuntime()
    {
        var localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
        var legacyRoots = new[]
        {
            Path.Combine(localAppData, "YMhut Box", "WinUI"),
            Path.Combine(localAppData, "YMhut Box"),
            Path.Combine(localAppData, "ymhut_box")
        };

        foreach (var root in legacyRoots)
        {
            foreach (var name in AppPaths.RuntimePayloadDirectoryNames)
            {
                TryDeleteDirectory(Path.Combine(root, name));
            }
        }
    }

    private static void TryDeleteDirectory(string directory)
    {
        try
        {
            if (Directory.Exists(directory))
            {
                Directory.Delete(directory, recursive: true);
            }
        }
        catch (Exception exception)
        {
            CrashLog.Write($"Unable to remove legacy runtime directory '{directory}': {exception.Message}");
        }
    }

    private static bool IsPackaged()
    {
        try
        {
            _ = Package.Current.Id.FullName;
            return true;
        }
        catch
        {
            return false;
        }
    }

    private static void ShowStartupError(string title, string message)
    {
        try
        {
            _ = MessageBoxW(IntPtr.Zero, message, title, 0x00000010);
        }
        catch
        {
        }
    }

    [DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = false)]
    private static extern int MessageBoxW(IntPtr hWnd, string text, string caption, uint type);
}
