defmodule MicrowavepropWeb.ImportLiveTest do
  use MicrowavepropWeb.ConnCase, async: true

  import Phoenix.LiveViewTest

  alias Microwaveprop.Radio.ImportRun
  alias Microwaveprop.Repo

  defp insert_run(attrs) do
    defaults = %{
      submitter_email: "importer@example.com",
      rows: %{"rows" => [], "refinement_ids" => []},
      total_rows: 10,
      processed_rows: 0,
      imported_count: 0,
      refined_count: 0,
      error_count: 0,
      errors: %{},
      status: "pending"
    }

    {:ok, run} =
      %ImportRun{}
      |> ImportRun.changeset(Map.merge(defaults, attrs))
      |> Repo.insert()

    run
  end

  describe "mount" do
    test "renders the initial state of a pending import", %{conn: conn} do
      run = insert_run(%{total_rows: 25, submitter_email: "alice@example.com"})

      {:ok, _lv, html} = live(conn, ~p"/imports/#{run.id}")

      assert html =~ "Contact Import"
      assert html =~ "alice@example.com"
      assert html =~ "25"
      assert html =~ ~r/id="import-status-badge"[^>]*>\s*Pending/
      assert html =~ ~s(id="import-progress-bar")
      assert html =~ ~s(id="import-imported-count")
      assert html =~ ~s(id="import-refined-count")
      assert html =~ ~s(id="import-error-count")
    end

    test "redirects to /submit with a flash when the import is not found", %{conn: conn} do
      missing_id = Ecto.UUID.generate()

      assert {:error, {:live_redirect, %{to: "/submit", flash: flash}}} =
               live(conn, ~p"/imports/#{missing_id}")

      assert flash["error"] =~ "Import not found"
    end

    test "redirects to /submit for an obviously bad id", %{conn: conn} do
      assert {:error, {:live_redirect, %{to: "/submit"}}} =
               live(conn, ~p"/imports/not-a-uuid")
    end
  end

  describe "live updates" do
    test "updates counters when an import_progress message is broadcast", %{conn: conn} do
      run = insert_run(%{total_rows: 100})

      {:ok, lv, _html} = live(conn, ~p"/imports/#{run.id}")

      updated = %{
        run
        | processed_rows: 50,
          imported_count: 48,
          refined_count: 1,
          error_count: 1,
          status: "running",
          errors: %{"7" => ["band is invalid"]}
      }

      Phoenix.PubSub.broadcast(
        Microwaveprop.PubSub,
        "csv_import:#{run.id}",
        {:import_progress, run.id, updated}
      )

      html = render(lv)

      assert html =~ ~r/id="import-imported-count"[^>]*>\s*48/
      assert html =~ ~r/id="import-refined-count"[^>]*>\s*1/
      assert html =~ ~r/id="import-error-count"[^>]*>\s*1/
      assert html =~ ~r/id="import-status-badge"[^>]*>\s*Running/
      assert html =~ "band is invalid"
    end

    test "shows the complete UI once status flips to complete", %{conn: conn} do
      run = insert_run(%{total_rows: 3})

      {:ok, lv, _html} = live(conn, ~p"/imports/#{run.id}")

      done = %{
        run
        | processed_rows: 3,
          imported_count: 3,
          status: "complete",
          completed_at: DateTime.utc_now()
      }

      Phoenix.PubSub.broadcast(
        Microwaveprop.PubSub,
        "csv_import:#{run.id}",
        {:import_progress, run.id, done}
      )

      html = render(lv)

      assert html =~ "Import complete"
      assert html =~ ~s(id="import-complete-panel")
      assert html =~ "View contacts"
      assert html =~ ~r/id="import-status-badge"[^>]*>\s*Complete/
    end

    test "shows the errors section when error_count > 0", %{conn: conn} do
      run =
        insert_run(%{
          total_rows: 2,
          processed_rows: 2,
          imported_count: 1,
          error_count: 1,
          status: "complete",
          errors: %{"2" => ["band is invalid"]}
        })

      {:ok, _lv, html} = live(conn, ~p"/imports/#{run.id}")

      assert html =~ ~s(id="import-errors-section")
      assert html =~ "Row 2"
      assert html =~ "band is invalid"
    end
  end
end
