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

  import Ecto.Query
  import Microwaveprop.AccountsFixtures
  import Microwaveprop.BeaconsFixtures
  import Phoenix.LiveViewTest

  alias Microwaveprop.Beacons
  alias Microwaveprop.Radio.Contact
  alias Microwaveprop.Repo

  defp contact_for(user, attrs) do
    defaults = %{
      station1: "W5XD",
      station2: "K5TR",
      qso_timestamp: ~U[2026-03-28 18:00:00Z],
      mode: "CW",
      band: Decimal.new("10000"),
      grid1: "EM12",
      grid2: "EM00",
      pos1: %{"lat" => 32.9, "lon" => -97.0},
      pos2: %{"lat" => 30.3, "lon" => -97.7},
      distance_km: Decimal.new("295"),
      user_id: user.id
    }

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

    contact
  end

  describe "mount" do
    test "renders a user's contributions", %{conn: conn} do
      user = user_fixture(%{callsign: "W5ISP"})
      _contact = contact_for(user, %{station1: "W5OWN"})
      _beacon = beacon_fixture(user, callsign: "W5ISP")

      {:ok, _lv, html} = live(conn, ~p"/u/#{user.callsign}")

      assert html =~ "W5ISP"
      assert html =~ "Contacts submitted"
      assert html =~ "Beacons submitted"
      assert html =~ "W5OWN"
    end

    test "callsign lookup is case-insensitive", %{conn: conn} do
      _user = user_fixture(%{callsign: "W5ISP"})

      {:ok, _lv, html} = live(conn, ~p"/u/w5isp")

      assert html =~ "W5ISP"
    end

    test "does not show contacts belonging to another user", %{conn: conn} do
      user = user_fixture(%{callsign: "W5ISP"})
      other = user_fixture(%{callsign: "W5OTH"})
      _owned = contact_for(user, %{station1: "W5MINE"})
      _theirs = contact_for(other, %{station1: "W5NOTMINE"})

      {:ok, _lv, html} = live(conn, ~p"/u/#{user.callsign}")

      assert html =~ "W5MINE"
      refute html =~ "W5NOTMINE"
    end

    test "shows empty-state messages when the user has no submissions", %{conn: conn} do
      user = user_fixture(%{callsign: "W5EMP"})

      {:ok, _lv, html} = live(conn, ~p"/u/#{user.callsign}")

      assert html =~ "No contacts submitted yet"
      assert html =~ "No beacons submitted yet"
    end

    test "redirects to the home page for an unknown callsign", %{conn: conn} do
      assert {:error, {:live_redirect, %{to: "/"}}} = live(conn, ~p"/u/NO1SUCH")
    end

    test "lists both approved and pending beacons so owners see their drafts", %{conn: conn} do
      user = user_fixture(%{callsign: "W5ISP"})
      {:ok, approved} = Beacons.create_beacon(user, valid_beacon_attrs())
      {:ok, _approved} = Beacons.approve_beacon(approved)
      _pending = beacon_fixture(user, callsign: "W5PND")

      {:ok, _lv, html} = live(conn, ~p"/u/#{user.callsign}")

      assert html =~ "W5PND"
      assert html =~ "Pending"
      assert html =~ "Approved"
    end

    test "renders the 'Contacts involving' section with contacts that mention the callsign as a remote station",
         %{conn: conn} do
      # The profile owner (W5ISP) isn't the submitter — another user logged
      # the contact — but W5ISP shows up as station2. The involving block
      # should surface that QSO.
      owner = user_fixture(%{callsign: "W5ISP"})
      other = user_fixture(%{callsign: "W5OTH"})
      _mention = contact_for(other, %{station1: "K5TR", station2: "W5ISP"})

      {:ok, _lv, html} = live(conn, ~p"/u/#{owner.callsign}")

      assert html =~ "Contacts W5ISP is in"
      assert html =~ "K5TR"
      assert html =~ "W5ISP"
    end

    test "uses first character of the user's name for the avatar initial when set", %{conn: conn} do
      _user = user_fixture(%{callsign: "W5ISP", name: "  graham mcintire"})

      {:ok, _lv, html} = live(conn, ~p"/u/W5ISP")

      # initial(%{name: "graham mcintire"}) trims, takes the first char,
      # and uppercases → "G". Assert on the font-mono span that renders it.
      assert html =~ ~r/font-mono[^>]*>\s*G\s*</s
    end

    test "falls back to the callsign's first character when name is an empty string",
         %{conn: conn} do
      # initial/1 guards `name != ""` so empty-string names fall through
      # to the callsign branch. Write the empty string directly via raw
      # SQL because the User changeset validates_required name.
      user = user_fixture(%{callsign: "W5ISP"})

      {1, _} =
        Repo.update_all(
          from(u in Microwaveprop.Accounts.User, where: u.id == ^user.id),
          set: [name: ""]
        )

      {:ok, _lv, html} = live(conn, ~p"/u/W5ISP")

      assert html =~ ~r/font-mono[^>]*>\s*W\s*</s
    end
  end
end
