using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEngine;

public static class Build
{
    public const string BuildPathOption = "-customBuildPath";
    public const string BuildTargetOption = "-buildTarget";
    public const string BuildOptionsOption = "-customBuildOptions";
    public const string ScriptingBackendOption = "-customScriptingBackend";

    public static void Perform()
    {
        var buildPath = GetRequiredOption(BuildPathOption);
        Console.WriteLine($"[Build] Custom build path '{buildPath}' detected.");

        var buildTargetName = GetRequiredOption(BuildTargetOption);
        var buildTarget = (BuildTarget)Enum.Parse(typeof(BuildTarget), buildTargetName);
        Console.WriteLine($"[Build] Build target '{buildTarget}' detected.");

        var scenes = EditorBuildSettings.scenes
            .Where(s => s.enabled && !string.IsNullOrWhiteSpace(s.path))
            .Select(s => s.path)
            .ToArray();
        Console.WriteLine($"[Build] Building the '{string.Join(", ", scenes)}' scenes.");

        var buildOptions = GetBuildOptions();
        Console.WriteLine($"[Build] Detected the '{buildOptions}' build options.");

        var targetGroup = BuildPipeline.GetBuildTargetGroup(buildTarget);
        Console.WriteLine($"[Build] Build target group resolved as '{targetGroup}'.");

        var scriptingBackendName = GetOption(ScriptingBackendOption);
        if (!string.IsNullOrWhiteSpace(scriptingBackendName))
        {
            var scriptingBackend = (ScriptingImplementation)Enum.Parse(
                typeof(ScriptingImplementation),
                scriptingBackendName);
            PlayerSettings.SetScriptingBackend(targetGroup, scriptingBackend);
        }
        Console.WriteLine($"[Build] Scripting backend set to '{PlayerSettings.GetScriptingBackend(targetGroup)}'.");

        var report = BuildPipeline.BuildPlayer(new BuildPlayerOptions
        {
            locationPathName = buildPath,
            scenes = scenes,
            target = buildTarget,
            targetGroup = targetGroup,
            options = buildOptions
        });

        if (report.summary.result != UnityEditor.Build.Reporting.BuildResult.Succeeded)
        {
            throw new InvalidOperationException($"[Build] Build failed with '{report.summary.result}'.");
        }
    }

    private static string GetOption(string optName)
    {
        var args = Environment.GetCommandLineArgs();
        var index = Array.IndexOf(args, optName);
        if (index < 0 || args.Length < index + 2 || string.IsNullOrWhiteSpace(args[index + 1]))
        {
            return null;
        }

        return args[index + 1];
    }

    private static string GetRequiredOption(string optName)
    {
        var option = GetOption(optName);
        if (option is null)
        {
            throw new InvalidOperationException($"The '{optName}' option is required.");
        }
        return option;
    }

    private static BuildOptions GetBuildOptions()
    {
        var buildOptionNames = (GetOption(BuildOptionsOption) ?? "").Split(',');
        var result = BuildOptions.None;
        foreach(var name in buildOptionNames)
        {
            if (Enum.TryParse<BuildOptions>(name, true, out var current))
            {
                result |= current;
            }
            else if (!string.IsNullOrWhiteSpace(name))
            {
                throw new NotSupportedException($"'{name}' is not a valid build option.");
            }
        }
        return result;
    }
}
