defmodule MicrowavepropWeb.RoverLocationsLive.ShowTest do
  use MicrowavepropWeb.ConnCase, async: true

  import Phoenix.LiveViewTest

  alias Microwaveprop.Radio.Maidenhead
  alias Microwaveprop.Repo
  alias Microwaveprop.Rover

  describe "show" do
    test "renders the location and a map container", %{conn: conn} do
      user = Microwaveprop.AccountsFixtures.user_fixture()

      {:ok, loc} =
        Rover.create_location(user, %{
          lat: 32.5,
          lon: -97.5,
          status: :good,
          notes: "great spot"
        })

      {:ok, lv, html} = live(conn, ~p"/rover-locations/#{loc.id}")

      assert html =~ "Rover Location"
      assert html =~ "great spot"
      assert html =~ "EM12gm"
      assert has_element?(lv, "#location-map-#{loc.id}[phx-hook=LocationMap]")
    end

    test "redirects when the location does not exist", %{conn: conn} do
      missing_id = Ecto.UUID.generate()

      assert {:error, {:live_redirect, %{to: "/rover-locations"}}} =
               live(conn, ~p"/rover-locations/#{missing_id}")
    end

    test "redirects when the id is not a valid UUID", %{conn: conn} do
      assert {:error, {:live_redirect, %{to: "/rover-locations"}}} =
               live(conn, ~p"/rover-locations/not-a-uuid")
    end

    test "owner sees a Delete button; visitors do not", %{conn: conn} do
      user = Microwaveprop.AccountsFixtures.user_fixture()
      {:ok, loc} = Rover.create_location(user, %{lat: 32.5, lon: -97.5, status: :good})

      # Anonymous: no Delete
      {:ok, _lv, html} = live(conn, ~p"/rover-locations/#{loc.id}")
      refute html =~ "Delete"

      # Owner: Delete present
      conn = log_in_user(conn, user)
      {:ok, _lv, html} = live(conn, ~p"/rover-locations/#{loc.id}")
      assert html =~ "Delete"
    end

    test "admin sees Delete on someone else's location", %{conn: conn} do
      owner = Microwaveprop.AccountsFixtures.user_fixture()
      admin = Microwaveprop.AccountsFixtures.user_fixture()
      {:ok, admin} = Microwaveprop.Accounts.admin_update_user(admin, %{is_admin: true})
      {:ok, loc} = Rover.create_location(owner, %{lat: 32.5, lon: -97.5, status: :good})

      conn = log_in_user(conn, admin)
      {:ok, _lv, html} = live(conn, ~p"/rover-locations/#{loc.id}")
      assert html =~ "Delete"
    end

    test "owner can enter edit mode and the marker is told to become draggable",
         %{conn: conn} do
      user = Microwaveprop.AccountsFixtures.user_fixture()
      {:ok, loc} = Rover.create_location(user, %{lat: 32.5, lon: -97.5, status: :good})
      conn = log_in_user(conn, user)

      {:ok, lv, _html} = live(conn, ~p"/rover-locations/#{loc.id}")

      html = lv |> element("button", "Edit") |> render_click()

      assert html =~ "Editing — drag the marker"
      # Save + Cancel show up; Edit button hides.
      assert has_element?(lv, "button[phx-click='save_edit']")
      assert has_element?(lv, "button[phx-click='cancel_edit']")
      refute has_element?(lv, "button[phx-click='toggle_edit']")
    end

    test "drag updates the working coords + grid (without persisting)", %{conn: conn} do
      user = Microwaveprop.AccountsFixtures.user_fixture()
      {:ok, loc} = Rover.create_location(user, %{lat: 32.5, lon: -97.5, status: :good})
      conn = log_in_user(conn, user)

      {:ok, lv, _html} = live(conn, ~p"/rover-locations/#{loc.id}")
      _ = lv |> element("button", "Edit") |> render_click()

      # Simulate the JS hook firing the dragend event.
      html = render_hook(lv, "location_dragged", %{"lat" => 33.25, "lon" => -97.75})

      assert html =~ "33.25"
      assert html =~ "-97.75"
      # Grid recomputed for the new coords.
      assert html =~ Maidenhead.from_latlon(33.25, -97.75, 10)

      # DB still has the original coords until Save is clicked.
      assert %{lat: 32.5, lon: -97.5} = Repo.reload(loc)
    end

    test "save persists the dragged coords to the DB", %{conn: conn} do
      user = Microwaveprop.AccountsFixtures.user_fixture()
      {:ok, loc} = Rover.create_location(user, %{lat: 32.5, lon: -97.5, status: :good})
      conn = log_in_user(conn, user)

      {:ok, lv, _html} = live(conn, ~p"/rover-locations/#{loc.id}")
      _ = lv |> element("button", "Edit") |> render_click()
      _ = render_hook(lv, "location_dragged", %{"lat" => 33.25, "lon" => -97.75})

      html = lv |> element("button[phx-click='save_edit']") |> render_click()
      assert html =~ "Location updated"

      reloaded = Repo.reload(loc)
      assert_in_delta reloaded.lat, 33.25, 1.0e-6
      assert_in_delta reloaded.lon, -97.75, 1.0e-6
    end

    test "cancel reverts the working coords without writing to the DB",
         %{conn: conn} do
      user = Microwaveprop.AccountsFixtures.user_fixture()
      {:ok, loc} = Rover.create_location(user, %{lat: 32.5, lon: -97.5, status: :good})
      conn = log_in_user(conn, user)

      {:ok, lv, _html} = live(conn, ~p"/rover-locations/#{loc.id}")
      _ = lv |> element("button", "Edit") |> render_click()
      _ = render_hook(lv, "location_dragged", %{"lat" => 99.0, "lon" => 99.0})

      html = lv |> element("button[phx-click='cancel_edit']") |> render_click()

      # Working coords reset to the stored values.
      assert html =~ "32.5"
      refute html =~ "99.0, 99.0"

      reloaded = Repo.reload(loc)
      assert reloaded.lat == 32.5
      assert reloaded.lon == -97.5
    end

    test "save_edit fails closed when the user is signed out mid-session", %{conn: conn} do
      user = Microwaveprop.AccountsFixtures.user_fixture()
      {:ok, loc} = Rover.create_location(user, %{lat: 32.5, lon: -97.5, status: :good})

      # Anonymous conn — driving the event directly through render_hook
      # exercises the unauthenticated branch of save_edit.
      {:ok, lv, _html} = live(conn, ~p"/rover-locations/#{loc.id}")

      html = render_hook(lv, "save_edit", %{})
      assert html =~ "Sign in required"
      assert Repo.reload(loc).lat == 32.5
    end

    test "edit mode exposes status + notes inputs populated with current values",
         %{conn: conn} do
      user = Microwaveprop.AccountsFixtures.user_fixture()

      {:ok, loc} =
        Rover.create_location(user, %{
          lat: 32.5,
          lon: -97.5,
          status: :good,
          notes: "first pass"
        })

      conn = log_in_user(conn, user)

      {:ok, lv, html} = live(conn, ~p"/rover-locations/#{loc.id}")
      # Inputs are not visible until edit mode is entered.
      refute has_element?(lv, "select[name='location[status]']")
      refute has_element?(lv, "textarea[name='location[notes]']")
      assert html =~ "first pass"

      _ = lv |> element("button", "Edit") |> render_click()

      assert has_element?(lv, "select[name='location[status]']")

      assert has_element?(
               lv,
               "textarea[name='location[notes]']",
               "first pass"
             )
    end

    test "save persists status + notes edits", %{conn: conn} do
      user = Microwaveprop.AccountsFixtures.user_fixture()

      {:ok, loc} =
        Rover.create_location(user, %{
          lat: 32.5,
          lon: -97.5,
          status: :good,
          notes: "old"
        })

      conn = log_in_user(conn, user)

      {:ok, lv, _html} = live(conn, ~p"/rover-locations/#{loc.id}")
      _ = lv |> element("button", "Edit") |> render_click()

      _ =
        lv
        |> form("#location-edit-form",
          location: %{status: "bad", notes: "private property"}
        )
        |> render_change()

      html = lv |> element("button[phx-click='save_edit']") |> render_click()
      assert html =~ "Location updated"

      reloaded = Repo.reload(loc)
      assert reloaded.status == :bad
      assert reloaded.notes == "private property"
    end

    test "cancel reverts pending status + notes changes", %{conn: conn} do
      user = Microwaveprop.AccountsFixtures.user_fixture()

      {:ok, loc} =
        Rover.create_location(user, %{
          lat: 32.5,
          lon: -97.5,
          status: :good,
          notes: "keeper"
        })

      conn = log_in_user(conn, user)

      {:ok, lv, _html} = live(conn, ~p"/rover-locations/#{loc.id}")
      _ = lv |> element("button", "Edit") |> render_click()

      _ =
        lv
        |> form("#location-edit-form",
          location: %{status: "bad", notes: "scratch this"}
        )
        |> render_change()

      _ = lv |> element("button[phx-click='cancel_edit']") |> render_click()

      reloaded = Repo.reload(loc)
      assert reloaded.status == :good
      assert reloaded.notes == "keeper"
    end

    test "non-owner does not see the Edit button", %{conn: conn} do
      owner = Microwaveprop.AccountsFixtures.user_fixture()
      visitor = Microwaveprop.AccountsFixtures.user_fixture()
      {:ok, loc} = Rover.create_location(owner, %{lat: 32.5, lon: -97.5, status: :good})
      conn = log_in_user(conn, visitor)

      {:ok, lv, _html} = live(conn, ~p"/rover-locations/#{loc.id}")
      refute has_element?(lv, "button[phx-click='toggle_edit']")
    end

    test "owner can delete from the show page and is redirected", %{conn: conn} do
      user = Microwaveprop.AccountsFixtures.user_fixture()
      {:ok, loc} = Rover.create_location(user, %{lat: 32.5, lon: -97.5, status: :good})
      conn = log_in_user(conn, user)

      {:ok, lv, _html} = live(conn, ~p"/rover-locations/#{loc.id}")

      assert {:ok, _index_lv, _html} =
               lv
               |> element("button", "Delete")
               |> render_click()
               |> follow_redirect(conn, ~p"/rover-locations")
    end
  end
end
