using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Windows.Forms;

[assembly: AssemblyVersion("1.11.1")]
[assembly: AssemblyFileVersion("1.11.1")]
[assembly: AssemblyInformationalVersion("1.11.1")]

internal sealed class EmbeddedFile
{
    public readonly string ResourceName;
    public readonly string RelativePath;

    public EmbeddedFile(string resourceName, string relativePath)
    {
        ResourceName = resourceName;
        RelativePath = relativePath;
    }
}

internal static class Program
{
    private static readonly EmbeddedFile[] Files = new EmbeddedFile[]
    {
        new EmbeddedFile("sura_installer_payload_0", "installer-manifest.json"),
        new EmbeddedFile("sura_installer_payload_1", "payload/SuraLanguage.exe"),
        new EmbeddedFile("sura_installer_payload_2", "payload/surapkg.exe"),
        new EmbeddedFile("sura_installer_payload_3", "README_INSTALL.md"),
        new EmbeddedFile("sura_installer_payload_4", "support/SuraLogo.ico"),
        new EmbeddedFile("sura_installer_payload_5", "support/SuraLogo.png"),
        new EmbeddedFile("sura_installer_payload_6", "support/SuraSetup.cmd"),
        new EmbeddedFile("sura_installer_payload_7", "support/SuraSetup.cs"),
        new EmbeddedFile("sura_installer_payload_8", "support/SuraSetup.ps1"),
        new EmbeddedFile("sura_installer_payload_9", "support/SuraSetup-GUI.ps1"),
        new EmbeddedFile("sura_installer_payload_10", "SuraSetup.exe")
    };

    [STAThread]
    private static void Main(string[] args)
    {
        try
        {
            Environment.Exit(Run(args));
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message, "Sura Language Setup", MessageBoxButtons.OK, MessageBoxIcon.Error);
            Environment.Exit(1);
        }
    }

    private static int Run(string[] args)
    {
        string extractOnly = GetArgValue(args, "--extract-only");
        if (!String.IsNullOrEmpty(extractOnly))
        {
            ExtractTo(Path.GetFullPath(extractOnly));
            return 0;
        }

        string quietInstall = GetArgValue(args, "--quiet-install");
        if (!String.IsNullOrEmpty(quietInstall))
        {
            string tempInstall = CreateTempDir();
            try
            {
                ExtractTo(tempInstall);
                return RunQuietInstall(tempInstall, Path.GetFullPath(quietInstall));
            }
            finally
            {
                DeleteTreeBestEffort(tempInstall);
            }
        }

        string temp = CreateTempDir();
        try
        {
            ExtractTo(temp);
            string setupExe = Path.Combine(temp, "SuraSetup.exe");
            if (!File.Exists(setupExe))
            {
                throw new InvalidOperationException("Embedded SuraSetup.exe was not found.");
            }

            ProcessStartInfo psi = new ProcessStartInfo(setupExe);
            psi.WorkingDirectory = temp;
            psi.UseShellExecute = true;
            psi.Arguments = JoinArguments(args);
            Process process = Process.Start(psi);
            process.WaitForExit();
            return process.ExitCode;
        }
        finally
        {
            DeleteTreeBestEffort(temp);
        }
    }

    private static string CreateTempDir()
    {
        string path = Path.Combine(Path.GetTempPath(), "sura_setup_" + Guid.NewGuid().ToString("N"));
        Directory.CreateDirectory(path);
        return path;
    }

    private static void ExtractTo(string directory)
    {
        Directory.CreateDirectory(directory);
        Assembly assembly = Assembly.GetExecutingAssembly();
        foreach (EmbeddedFile file in Files)
        {
            string outputPath = Path.Combine(directory, file.RelativePath.Replace('/', Path.DirectorySeparatorChar));
            string parent = Path.GetDirectoryName(outputPath);
            if (!String.IsNullOrEmpty(parent))
            {
                Directory.CreateDirectory(parent);
            }

            using (Stream input = assembly.GetManifestResourceStream(file.ResourceName))
            {
                if (input == null)
                {
                    throw new InvalidOperationException("Missing embedded installer resource: " + file.ResourceName);
                }
                using (FileStream output = new FileStream(outputPath, FileMode.Create, FileAccess.Write))
                {
                    input.CopyTo(output);
                }
            }
        }
    }

    private static int RunQuietInstall(string extractedRoot, string installDir)
    {
        string script = Path.Combine(Path.Combine(extractedRoot, "support"), "SuraSetup.ps1");
        if (!File.Exists(script))
        {
            throw new InvalidOperationException("Embedded SuraSetup.ps1 was not found.");
        }

        ProcessStartInfo psi = new ProcessStartInfo(PowerShellPath());
        psi.WorkingDirectory = extractedRoot;
        psi.UseShellExecute = false;
        psi.CreateNoWindow = true;
        psi.Arguments = "-NoProfile -ExecutionPolicy Bypass -File " + Quote(script) + " -InstallDir " + Quote(installDir) + " -NoPath -Quiet";
        Process process = Process.Start(psi);
        process.WaitForExit();
        return process.ExitCode;
    }

    private static string GetArgValue(string[] args, string name)
    {
        for (int i = 0; i < args.Length; i++)
        {
            if (String.Equals(args[i], name, StringComparison.OrdinalIgnoreCase))
            {
                if (i + 1 >= args.Length)
                {
                    throw new ArgumentException(name + " requires a path.");
                }
                return args[i + 1];
            }
            if (args[i].StartsWith(name + "=", StringComparison.OrdinalIgnoreCase))
            {
                return args[i].Substring(name.Length + 1);
            }
        }
        return "";
    }

    private static string PowerShellPath()
    {
        string ps = Path.Combine(Environment.SystemDirectory, "WindowsPowerShell\\v1.0\\powershell.exe");
        if (File.Exists(ps))
        {
            return ps;
        }
        return "powershell.exe";
    }

    private static string JoinArguments(string[] args)
    {
        string[] quoted = new string[args.Length];
        for (int i = 0; i < args.Length; i++)
        {
            quoted[i] = Quote(args[i]);
        }
        return String.Join(" ", quoted);
    }

    private static string Quote(string value)
    {
        if (value == null)
        {
            value = "";
        }
        return "\"" + value.Replace("\\", "\\\\").Replace("\"", "\\\"") + "\"";
    }

    private static void DeleteTreeBestEffort(string path)
    {
        try
        {
            if (Directory.Exists(path))
            {
                Directory.Delete(path, true);
            }
        }
        catch
        {
        }
    }
}