using System.Text.RegularExpressions;
using DeepDrftPublic.Client.Helpers;

namespace DeepDrftTests;

/// <summary>
/// Unit tests for the share-popover embed snippet (<see cref="EmbedSnippetBuilder"/>). The builder is
/// the mode-aware half of SharePopover: track mode targets FramePlayer's TrackEntryKey param, release
/// mode targets its ReleaseEntryKey param. The two snippets share width/border/autoplay chrome but
/// diverge in height by design (Phase 17 §4.1, OQ6): the release embed is taller to show its queue
/// panel; the track embed stays compact. Pure string composition, tested without rendering.
/// </summary>
[TestFixture]
public class EmbedSnippetBuilderTests
{
    private const string BaseUri = "https://deepdrft.example/";

    [Test]
    public void ForTrack_EmitsTrackEntryKeySrc()
    {
        var snippet = EmbedSnippetBuilder.ForTrack(BaseUri, "abc123");

        Assert.That(snippet, Does.Contain(@"src=""https://deepdrft.example/FramePlayer?TrackEntryKey=abc123"""));
        Assert.That(snippet, Does.Not.Contain("ReleaseEntryKey"));
    }

    [Test]
    public void ForRelease_EmitsReleaseEntryKeySrc()
    {
        var snippet = EmbedSnippetBuilder.ForRelease(BaseUri, "rel-xyz");

        // src contains ReleaseEntryKey; may also carry additional query params (e.g. EmbedId).
        Assert.That(snippet, Does.Contain("ReleaseEntryKey=rel-xyz"));
        Assert.That(snippet, Does.Not.Contain("TrackEntryKey"));
    }

    [Test]
    public void BothModes_ShareIdenticalNonHeightChrome()
    {
        var track = EmbedSnippetBuilder.ForTrack(BaseUri, "k");
        var release = EmbedSnippetBuilder.ForRelease(BaseUri, "k");

        Assert.Multiple(() =>
        {
            foreach (var snippet in new[] { track, release })
            {
                Assert.That(snippet, Does.StartWith("<iframe "));
                Assert.That(snippet, Does.Contain(@"width=""656"""));
                Assert.That(snippet, Does.Contain(@"frameborder=""0"""));
                Assert.That(snippet, Does.Contain(@"style=""border-radius:8px;"""));
                Assert.That(snippet, Does.Contain(@"allow=""autoplay"""));
                Assert.That(snippet, Does.Contain("</iframe>"));
            }
        });
    }

    // T14 (Phase 17 §9): the release embed is taller than the track embed (it shows a queue panel),
    // and the track embed's height is unchanged from its historical value (UC6/AC6).
    [Test]
    public void ForTrack_KeepsHistoricalCompactHeight()
    {
        var track = EmbedSnippetBuilder.ForTrack(BaseUri, "k");

        Assert.That(track, Does.Contain(@"height=""196"""));
    }

    [Test]
    public void ForRelease_IsTallerThanForTrack_ToShowQueuePanel()
    {
        var trackHeight = HeightOf(EmbedSnippetBuilder.ForTrack(BaseUri, "k"));
        var releaseHeight = HeightOf(EmbedSnippetBuilder.ForRelease(BaseUri, "k"));

        Assert.That(releaseHeight, Is.GreaterThan(trackHeight));
    }

    // The release snippet carries the host-side resize listener (OQ1 Option A); the track snippet,
    // having no panel to collapse, does not.
    [Test]
    public void ForRelease_IncludesResizeListenerScript()
    {
        var release = EmbedSnippetBuilder.ForRelease(BaseUri, "k");

        Assert.Multiple(() =>
        {
            Assert.That(release, Does.Contain("<script>"));
            Assert.That(release, Does.Contain("deepdrft-embed-resize"));
        });
    }

    [Test]
    public void ForTrack_HasNoResizeListenerScript()
    {
        var track = EmbedSnippetBuilder.ForTrack(BaseUri, "k");

        Assert.That(track, Does.Not.Contain("<script>"));
    }

    // --- Multi-embed isolation (Phase 17 major remediation) ---

    // Two ForRelease calls must produce snippets with different iframe ids so both can coexist on one
    // host page without the host-side resize script resolving only the first via getElementById.
    [Test]
    public void ForRelease_TwoCalls_ProduceDifferentIframeIds()
    {
        var a = EmbedSnippetBuilder.ForRelease(BaseUri, "rel-xyz");
        var b = EmbedSnippetBuilder.ForRelease(BaseUri, "rel-xyz"); // same release, different call

        var idA = IframeId(a);
        var idB = IframeId(b);

        Assert.That(idA, Is.Not.EqualTo(idB),
            "each ForRelease call must mint a distinct iframe id to prevent multi-embed cross-talk");
    }

    // The iframe id and the token embedded in the host-side resize script must be consistent within
    // a single snippet — the script assigns the id string to a JS variable and calls getElementById
    // with it, so the id literal must appear in the script's var initializer.
    [Test]
    public void ForRelease_IframeIdAndScriptToken_AreConsistentWithinOneSnippet()
    {
        var snippet = EmbedSnippetBuilder.ForRelease(BaseUri, "rel-abc");

        var id = IframeId(snippet);
        Assert.That(id, Does.StartWith("deepdrft-embed-"), "id must carry the expected prefix");

        // The iframe element must declare the minted id.
        Assert.That(snippet, Does.Contain($@"id=""{id}"""),
            "iframe element must carry the minted id");

        // The script stores the id in a JS var and calls getElementById(id) — confirm the id literal
        // appears in the script's var initializer so the right iframe is targeted.
        Assert.That(snippet, Does.Contain($@"var id=""{id}"""),
            "resize script must initialise its id variable with the same minted id");
    }

    // The iframe src must carry EmbedId so the iframe content (embed-frame.ts) can read its own
    // token and include it in postMessage payloads for the host-side script to match on.
    [Test]
    public void ForRelease_SrcCarriesEmbedIdParam()
    {
        var snippet = EmbedSnippetBuilder.ForRelease(BaseUri, "rel-def");

        Assert.That(snippet, Does.Contain("EmbedId="),
            "iframe src must include EmbedId query param so embed-frame.ts can read its own token");
    }

    private static int HeightOf(string snippet)
    {
        var match = Regex.Match(snippet, @"height=""(\d+)""");
        Assert.That(match.Success, Is.True, "snippet must declare an iframe height");
        return int.Parse(match.Groups[1].Value);
    }

    private static string IframeId(string snippet)
    {
        var match = Regex.Match(snippet, @"id=""([^""]+)""");
        Assert.That(match.Success, Is.True, "snippet must declare an iframe id");
        return match.Groups[1].Value;
    }
}
