using System.Diagnostics;
using Prexonite.Compiler.Build.Internal;

namespace Prexonite.Compiler.Build;

public static class Plan
{
    public static readonly TraceSource Trace = new("Prexonite.Compiler.Build");

    /// <summary>List of modules included in the Prexonite assembly. Does not include 'sys' itself.</summary>
    static readonly ISource[] _stdLibModules =
    [
        Source.FromEmbeddedPrexoniteResource("prxlib.prx.prim.pxs"),
        Source.FromEmbeddedPrexoniteResource("prxlib.prx.core.pxs"),
        Source.FromEmbeddedPrexoniteResource("prxlib.sys.pxs"),
        Source.FromEmbeddedPrexoniteResource("prxlib.prx.v1.pxs"),
        Source.FromEmbeddedPrexoniteResource("prxlib.prx.v1.prelude.pxs"),
        Source.FromEmbeddedPrexoniteResource("prxlib.prx.v2.prelude.pxs"),
    ];

    public static IPlan CreateDefault()
    {
        return new IncrementalPlan();
    }

    public static ISelfAssemblingPlan CreateSelfAssembling()
    {
        // ReSharper disable once IntroduceOptionalParameters.Global
        return CreateSelfAssembling(StandardLibraryPreference.Default);
    }

    public static async Task<ISelfAssemblingPlan> CreateSelfAssemblingAsync(
        StandardLibraryPreference stdPreference,
        CancellationToken token
    )
    {
        var plan = new SelfAssemblingPlan();
        if (
            stdPreference
            is StandardLibraryPreference.Default
                or StandardLibraryPreference.NoPrelude
        )
        {
            // Provide modules that the standard library may be composed of. No dependency checking.
            await Task.WhenAll(_stdLibModules.Select(s => plan.RegisterModule(s, token)));

            // Describe standard library. Dependencies must be satisfied
            plan.StandardLibrary.Add(new("sys", new(0, 0)));
            if (stdPreference != StandardLibraryPreference.NoPrelude)
            {
                plan.StandardLibrary.Add(new("prx.prelude", new(2, 0)));
            }
        }
        return plan;
    }

    public static ISelfAssemblingPlan CreateSelfAssembling(StandardLibraryPreference stdPreference)
    {
        return CreateSelfAssemblingAsync(stdPreference, CancellationToken.None).Result;
    }
}

public enum StandardLibraryPreference
{
    Default = 0,
    NoPrelude = 1,
    None,
}
