using NUnit.Framework;
using Shouldly;

namespace ErsatzTV.Tests;

[TestFixture]
public class StartupSpaHostingTests
{
    private static readonly string StartupSource = File.ReadAllText(FindStartupPath());

    [Test]
    public void Startup_Should_Mount_ChicoryTv_Spa_At_App_Path()
    {
        StartupSource.ShouldContain("ctx.Request.Path.StartsWithSegments(\"/app\")");
        StartupSource.ShouldContain("MapWhen(");
        StartupSource.ShouldContain("SpaStaticFileRoot");
        StartupSource.ShouldContain("RequestPath = \"/app\"");
        StartupSource.ShouldContain("appIndexFile");
    }

    [Test]
    public void Startup_Should_Keep_App_Routes_Out_Of_The_Legacy_Catch_All()
    {
        // /app is excluded from the legacy branch's MapWhen predicate, so SPA routes never
        // reach the catch-all fallback (which 302s unmatched non-API paths to /app — an
        // included /app route would loop).
        StartupSource.ShouldContain("!IsSpaPath(ctx.Request.Path)");
        StartupSource.ShouldContain("bool IsSpaPath(PathString path)");
    }

    [Test]
    public void Startup_Should_Have_Removed_The_Blazor_Server_Ui()
    {
        // ersatztv#91 phase (b): the legacy Blazor Server UI is deleted. Guard against
        // reintroduction — none of its wiring may return.
        StartupSource.ShouldNotContain("MapBlazorHub");
        StartupSource.ShouldNotContain("_Host");
        StartupSource.ShouldNotContain("AddServerSideBlazor");
        StartupSource.ShouldNotContain("AddMudServices");
        StartupSource.ShouldNotContain("AddRazorPages");
    }

    [Test]
    public void Startup_Should_Catch_All_Unmatched_Legacy_Routes_To_The_Spa()
    {
        // With _Host gone, a retired Blazor route that matches no controller/redirect 302s to
        // the SPA rather than hard-404ing; /api, /artwork, /docs, /openapi are excluded so an
        // unmatched one of those is a genuine 404 (docs/decisions.md #204).
        StartupSource.ShouldContain("endpoints.MapFallback(");
        StartupSource.ShouldContain("context.Response.Redirect(context.Request.PathBase + \"/app\")");
        StartupSource.ShouldContain("path.StartsWithSegments(\"/api\")");
        StartupSource.ShouldContain("path.StartsWithSegments(\"/artwork\")");
    }

    private static string FindStartupPath()
    {
        DirectoryInfo? directory = new(TestContext.CurrentContext.TestDirectory);

        while (directory is not null)
        {
            string candidate = Path.Combine(directory.FullName, "ErsatzTV", "Startup.cs");
            if (File.Exists(candidate))
            {
                return candidate;
            }

            directory = directory.Parent;
        }

        throw new FileNotFoundException("Could not find ErsatzTV/Startup.cs");
    }
}
