defmodule MicrowavepropWeb.BeaconLive.Form do
  @moduledoc false
  use MicrowavepropWeb, :live_view

  alias Microwaveprop.Beacons
  alias Microwaveprop.Beacons.Beacon

  @impl true
  def render(assigns) do
    ~H"""
    <Layouts.app flash={@flash} current_scope={@current_scope}>
      <.header>
        {@page_title}
        <:subtitle>
          Enter either a grid or lat/lon — whichever you leave blank is filled in
          from the other.
        </:subtitle>
      </.header>

      <.form for={@form} id="beacon-form" phx-change="validate" phx-submit="save">
        <.input
          field={@form[:frequency_mhz]}
          type="text"
          label="Frequency (MHz)"
          inputmode="decimal"
          phx-hook="CommaNumber"
          required
        />
        <.input field={@form[:callsign]} type="text" label="Call" required />
        <.input field={@form[:grid]} type="text" label="Grid" />
        <.input field={@form[:lat]} type="number" label="Latitude" step="any" />
        <.input field={@form[:lon]} type="number" label="Longitude" step="any" />
        <.input
          field={@form[:power_mw]}
          type="number"
          label="TX power (EIRP) (mW)"
          step="any"
          required
        />
        <.input
          field={@form[:height_ft]}
          type="number"
          label="Height above ground (ft)"
          required
        />
        <.input
          field={@form[:bearing]}
          type="text"
          label="Bearing"
          placeholder="omni or 0-360 degrees"
        />
        <.input
          field={@form[:beamwidth_deg]}
          type="number"
          label="Beamwidth (degrees)"
          step="any"
          placeholder="Leave blank for omni"
        />
        <.input
          field={@form[:keying]}
          type="select"
          label="Keying"
          options={Beacon.keying_options()}
          required
        />
        <.input field={@form[:on_the_air]} type="checkbox" label="On the air" />
        <.input field={@form[:notes]} type="textarea" label="Notes" />
        <footer>
          <.button phx-disable-with="Saving..." variant="primary">Save Beacon</.button>
          <.button navigate={return_path(@return_to, @beacon)}>Cancel</.button>
        </footer>
      </.form>
    </Layouts.app>
    """
  end

  @impl true
  def mount(params, _session, socket) do
    {:ok,
     socket
     |> assign(:return_to, return_to(params["return_to"]))
     |> apply_action(socket.assigns.live_action, params)}
  end

  defp return_to("show"), do: "show"
  defp return_to(_), do: "index"

  defp apply_action(socket, :edit, %{"id" => id}) do
    beacon = Beacons.get_beacon!(id)

    socket
    |> assign(:page_title, "Edit beacon")
    |> assign(:beacon, beacon)
    |> assign(:form, to_form(Beacons.change_beacon(beacon)))
  end

  defp apply_action(socket, :new, _params) do
    beacon = %Beacon{}

    socket
    |> assign(:page_title, "New beacon")
    |> assign(:beacon, beacon)
    |> assign(:form, to_form(Beacons.change_beacon(beacon)))
  end

  @impl true
  def handle_event("validate", %{"beacon" => beacon_params}, socket) do
    changeset = Beacons.change_beacon(socket.assigns.beacon, strip_commas(beacon_params))
    {:noreply, assign(socket, form: to_form(changeset, action: :validate))}
  end

  def handle_event("save", %{"beacon" => beacon_params}, socket) do
    save_beacon(socket, socket.assigns.live_action, strip_commas(beacon_params))
  end

  defp strip_commas(params) do
    params
    |> Map.update("frequency_mhz", nil, fn
      v when is_binary(v) -> String.replace(v, ",", "")
      v -> v
    end)
    |> Map.update("height_ft", nil, fn
      v when is_binary(v) -> String.replace(v, ~r/\.0*$/, "")
      v -> v
    end)
  end

  defp save_beacon(socket, :edit, beacon_params) do
    case Beacons.update_beacon(socket.assigns.beacon, beacon_params) do
      {:ok, beacon} ->
        {:noreply,
         socket
         |> put_flash(:info, "Beacon updated")
         |> push_navigate(to: return_path(socket.assigns.return_to, beacon))}

      {:error, %Ecto.Changeset{} = changeset} ->
        {:noreply, assign(socket, form: to_form(changeset))}
    end
  end

  defp save_beacon(socket, :new, beacon_params) do
    user = current_user(socket.assigns.current_scope)

    case Beacons.create_beacon(user, beacon_params) do
      {:ok, beacon} ->
        flash =
          if user,
            do: "Beacon submitted — pending admin approval.",
            else: "Thanks! Your beacon has been submitted and is awaiting admin approval."

        {:noreply,
         socket
         |> put_flash(:info, flash)
         |> push_navigate(to: return_path(socket.assigns.return_to, beacon))}

      {:error, %Ecto.Changeset{} = changeset} ->
        {:noreply, assign(socket, form: to_form(changeset))}
    end
  end

  defp current_user(%{user: user}), do: user
  defp current_user(_), do: nil

  defp return_path("index", _beacon), do: ~p"/beacons"
  defp return_path("show", beacon), do: ~p"/beacons/#{beacon}"
end
