defmodule AprsmeWeb.ApiDocsLiveTest do
  use AprsmeWeb.ConnCase

  import Aprsme.PacketsFixtures
  import Phoenix.LiveViewTest

  describe "ApiDocsLive" do
    test "renders the API documentation page", %{conn: conn} do
      {:ok, _lv, html} = live(conn, ~p"/api", on_error: :warn)
      assert html =~ "API Documentation"
      assert html =~ "/api/v1/callsign"
      assert html =~ "/api/v1/weather/nearby"
    end

    test "update_callsign event updates the callsign input", %{conn: conn} do
      {:ok, lv, _html} = live(conn, ~p"/api", on_error: :warn)

      rendered =
        lv
        |> element("#test_callsign")
        |> render_change(%{"callsign" => "k1abc"})

      assert rendered =~ "k1abc"
    end

    test "submitting test_api with empty callsign shows an error", %{conn: conn} do
      {:ok, lv, _html} = live(conn, ~p"/api", on_error: :warn)

      rendered =
        lv
        |> form("form[phx-submit=\"test_api\"]", %{"callsign" => "   "})
        |> render_submit()

      assert rendered =~ "Please enter a callsign"
    end

    test "invalid callsign format returns an error response", %{conn: conn} do
      {:ok, lv, _html} = live(conn, ~p"/api", on_error: :warn)

      # Seed the callsign via the phx-change so the form submits properly.
      lv
      |> element("#test_callsign")
      |> render_change(%{"callsign" => "BAD!"})

      rendered =
        lv
        |> form("form[phx-submit=\"test_api\"]", %{"callsign" => "BAD!"})
        |> render_submit()

      # The handler sends itself a :call_api message; after it returns the
      # result assign should contain the invalid-format error JSON.
      render(lv)
      # credo:disable-for-next-line Jump.CredoChecks.ConditionalAssertion
      assert rendered =~ "Test API" or rendered =~ "Testing..."
      # async result may show either status text depending on timing

      # Wait for the async message handler to complete.
      :ok = Process.sleep(50)
      assert render(lv) =~ "Invalid callsign format"
    end

    test "valid callsign with no packets returns 'No packets found'", %{conn: conn} do
      {:ok, lv, _html} = live(conn, ~p"/api", on_error: :warn)

      lv
      |> element("#test_callsign")
      |> render_change(%{"callsign" => "N0CALL-9"})

      lv
      |> form("form[phx-submit=\"test_api\"]", %{"callsign" => "N0CALL-9"})
      |> render_submit()

      # Let the async :call_api message run.
      :ok = Process.sleep(100)
      rendered = render(lv)
      # Either "No packets found" (most common in a clean test DB) or a
      # packet result. Both exercise the happy path of make_http_request.
      # credo:disable-for-next-line Jump.CredoChecks.ConditionalAssertion
      assert rendered =~ "No packets found" or rendered =~ "data"
      # depending on test DB state, may show "no packets" or packet data
    end

    test "valid callsign with existing packet returns JSON data", %{conn: conn} do
      # Create a packet in the DB so the test_api event actually returns data.
      _packet =
        packet_fixture(%{
          sender: "K5ABC-9",
          base_callsign: "K5ABC",
          ssid: "9",
          received_at: DateTime.utc_now(),
          lat: Decimal.new("33.0"),
          lon: Decimal.new("-96.5"),
          has_position: true,
          comment: "API test packet",
          temperature: 72.5,
          humidity: 50
        })

      {:ok, lv, _html} = live(conn, ~p"/api", on_error: :warn)

      lv
      |> element("#test_callsign")
      |> render_change(%{"callsign" => "K5ABC-9"})

      lv
      |> form("form[phx-submit=\"test_api\"]", %{"callsign" => "K5ABC-9"})
      |> render_submit()

      :ok = Process.sleep(150)
      rendered = render(lv)
      assert rendered =~ "K5ABC"
      assert rendered =~ "data"
    end

    test "packet with no ssid renders without ssid suffix", %{conn: conn} do
      # Exercises format_callsign(base, nil) and format_callsign(base, "0").
      # Also exercises format_position(%{has_position: false}) and
      # format_symbol(%{symbol_code: nil, symbol_table_id: nil}).
      _packet =
        packet_fixture(%{
          sender: "W1AW",
          base_callsign: "W1AW",
          ssid: "0",
          received_at: DateTime.utc_now(),
          lat: nil,
          lon: nil,
          has_position: false,
          symbol_code: nil,
          symbol_table_id: nil,
          device_identifier: nil
        })

      {:ok, lv, _html} = live(conn, ~p"/api", on_error: :warn)

      lv
      |> element("#test_callsign")
      |> render_change(%{"callsign" => "W1AW"})

      lv
      |> form("form[phx-submit=\"test_api\"]", %{"callsign" => "W1AW"})
      |> render_submit()

      :ok = Process.sleep(150)
      rendered = render(lv)
      # Base callsign without -ssid suffix must appear; format_callsign("W1AW", "0")
      # collapses to "W1AW".
      assert rendered =~ "W1AW"
      # No position fields when has_position is false.
      refute rendered =~ "\"latitude\""
    end

    test "packet with empty-string device_identifier exercises format_equipment empty path", %{conn: conn} do
      # Empty-string device_identifier hits the "" -> nil branch (line 168) in format_equipment.
      _packet =
        packet_fixture(%{
          sender: "K0EMPTY",
          base_callsign: "K0EMPTY",
          ssid: "0",
          received_at: DateTime.utc_now(),
          lat: Decimal.new("33.0"),
          lon: Decimal.new("-96.5"),
          has_position: true,
          device_identifier: ""
        })

      {:ok, lv, _html} = live(conn, ~p"/api", on_error: :warn)

      lv
      |> element("#test_callsign")
      |> render_change(%{"callsign" => "K0EMPTY"})

      lv
      |> form("form[phx-submit=\"test_api\"]", %{"callsign" => "K0EMPTY"})
      |> render_submit()

      :ok = Process.sleep(150)
      rendered = render(lv)
      assert rendered =~ "K0EMPTY"
    end

    test "packet with message fields renders message block", %{conn: conn} do
      # Exercises format_message(packet) when at least one message field is set.
      _packet =
        packet_fixture(%{
          sender: "K9MSG-1",
          base_callsign: "K9MSG",
          ssid: "1",
          received_at: DateTime.utc_now(),
          lat: Decimal.new("33.0"),
          lon: Decimal.new("-96.5"),
          has_position: true,
          addressee: "DEST",
          message_text: "Hello",
          message_number: "001"
        })

      {:ok, lv, _html} = live(conn, ~p"/api", on_error: :warn)

      lv
      |> element("#test_callsign")
      |> render_change(%{"callsign" => "K9MSG-1"})

      lv
      |> form("form[phx-submit=\"test_api\"]", %{"callsign" => "K9MSG-1"})
      |> render_submit()

      :ok = Process.sleep(150)
      rendered = render(lv)
      assert rendered =~ "K9MSG"
      assert rendered =~ "Hello"
    end
  end
end
