alias FirehoseWeb.MicroprintsLive

defmodule FirehoseWeb.MicroprintsLiveTest do
  use FirehoseWeb.ConnCase, async: true

  import Phoenix.LiveViewTest

  describe "scan_source_files/0" do
    test "returns exactly 2 files" do
      files = FirehoseWeb.MicroprintsLive.scan_source_files()

      assert length(files) == 2
    end

    test "returns only .ex files from app/ and blogex/ directories" do
      files = FirehoseWeb.MicroprintsLive.scan_source_files()

      # With the 2-file limit, check that returned files are valid .ex paths
      Enum.each(files, fn file ->
        assert String.ends_with?(file, ".ex")
        assert String.starts_with?(file, "lib/") or String.starts_with?(file, "../blogex/")
      end)
    end

    test "does not include files from _build/ directory" do
      files = FirehoseWeb.MicroprintsLive.scan_source_files()

      refute Enum.any?(files, &String.starts_with?(&1, "_build/"))
    end

    test "does not include files from deps/ directory" do
      files = FirehoseWeb.MicroprintsLive.scan_source_files()

      refute Enum.any?(files, &String.starts_with?(&1, "deps/"))
    end

    test "does not include files from examples/ directory" do
      files = FirehoseWeb.MicroprintsLive.scan_source_files()

      refute Enum.any?(files, &String.contains?(&1, "/examples/"))
    end

    test "does not include test files" do
      files = FirehoseWeb.MicroprintsLive.scan_source_files()

      refute Enum.any?(files, &String.contains?(&1, "/test/"))
    end

    test "paths are relative (no leading slash or absolute path)" do
      files = FirehoseWeb.MicroprintsLive.scan_source_files()

      refute Enum.any?(files, &String.starts_with?(&1, "/"))
    end

    test "app paths do not contain source dir prefix" do
      files = FirehoseWeb.MicroprintsLive.scan_source_files()

      app_files = Enum.filter(files, &String.starts_with?(&1, "lib/"))
      refute Enum.any?(app_files, &String.starts_with?(&1, "app/"))
    end

    test "blogex paths start with ../blogex/" do
      files = FirehoseWeb.MicroprintsLive.scan_source_files()

      blogex_files = Enum.filter(files, &String.starts_with?(&1, "../blogex/"))
      # With the 2-file limit, blogex files may or may not be included
      # depending on which files are most recently modified
      assert is_list(blogex_files)
    end
  end

  describe "expanded_path and highlighted_path coupling" do
    test "expanding file A and highlighting a line in file B should collapse file A", %{
      conn: conn
    } do
      files = MicroprintsLive.scan_source_files()
      assert length(files) >= 2, "Need at least 2 files to test coupling"

      [file_a, file_b | _] = files

      {:ok, view, _html} = live(conn, ~p"/microprints")

      # Expand file A
      view
      |> element("button[phx-value-path=\"#{file_a}\"]", "Expand")
      |> render_click()

      # Verify file A shows "Collapse" button (it's expanded)
      html = render(view)
      assert html =~ ~s(phx-value-path="#{file_a}")
      assert html =~ "Collapse"

      # Highlight a line in file B by dispatching the highlight_line event
      # (microprint renders multiple rect segments per line, element() can't pick one)
      render_click(view, "highlight_line", %{"line" => "1", "path" => file_b})

      # file A should be collapsed when highlighting a different file
      html = render(view)

      refute html =~ "Collapse",
             "file A should be collapsed after highlighting a different file, but the Collapse button is still visible (expanded_path is uncoupled from highlighted_path)"
    end

    test "switching expand from file A to file B shows each file's own source content", %{
      conn: conn
    } do
      files = MicroprintsLive.scan_source_files()
      assert length(files) >= 2, "Need at least 2 files to test source switching"

      [file_a, file_b | _] = files

      {:ok, view, _html} = live(conn, ~p"/microprints")

      # Expand file A
      view
      |> element("button[phx-value-path=\"#{file_a}\"]", "Expand")
      |> render_click()

      # Capture file A's source content from the rendered HTML
      html_a = render(view)
      # Each .ex file starts with "defmodule", grab the first defmodule line as unique content
      assert html_a =~ "defmodule",
             "File A source should be visible when expanded"

      # Expand file B (should auto-collapse A)
      view
      |> element("button[phx-value-path=\"#{file_b}\"]", "Expand")
      |> render_click()

      # Capture file B's source content
      html_b = render(view)

      # The two source viewers must show different content
      refute html_a == html_b,
             "Source content should differ when switching between files"

      # File A's button should now say "Expand" (collapsed)
      refute html_b =~ ~r(phx-value-path="#{Regex.escape(file_a)}"[^>]*>\s*Collapse\s*</),
             "file A should be collapsed after switching expand to file B"

      # File B's button should say "Collapse" (expanded)
      assert html_b =~ ~r(phx-value-path="#{Regex.escape(file_b)}"[^>]*>\s*Collapse\s*</),
             "file B should show Collapse button when expanded"
    end
  end

  describe "app layout with menu" do
    test "renders the microprints page", %{conn: conn} do
      {:ok, _view, html} = live(conn, ~p"/microprints")
      assert html =~ "Microprints"
    end

    test "renders with page content and legend", %{conn: conn} do
      {:ok, _view, html} = live(conn, ~p"/microprints")
      # Verify the page renders expected content (render/1 returns LV inner HTML only)
      assert html =~ "Visual fingerprints of source code files"
      assert html =~ "Function"
      assert html =~ "Module"
      assert html =~ "Keyword"
    end
  end

  describe "URL state persistence" do
    test "expanded path is restored from query param on mount", %{conn: conn} do
      files = MicroprintsLive.scan_source_files()
      file_a = List.first(files)

      {:ok, view, _html} = live(conn, ~p"/microprints?expanded=#{file_a}")

      html = render(view)

      assert html =~ "Collapse",
             "Expanded file should show Collapse button when restored from URL param"

      assert html =~ ~s(phx-value-path="#{file_a}")
    end

    test "unknown expanded path in URL is ignored gracefully", %{conn: conn} do
      {:ok, view, _html} = live(conn, ~p"/microprints?expanded=nonexistent.ex")

      html = render(view)

      refute html =~ "Collapse",
             "Nonexistent expanded path should not show Collapse"
    end

    test "expand updates URL with expanded param", %{conn: conn} do
      files = MicroprintsLive.scan_source_files()
      file_a = List.first(files)

      {:ok, view, _html} = live(conn, ~p"/microprints")

      view
      |> element("button[phx-value-path=\"#{file_a}\"]", "Expand")
      |> render_click()

      # URL should contain expanded param after clicking Expand
      html = render(view)

      assert html =~ "Collapse",
             "File should remain expanded after push_patch updates URL"
    end
  end
end
