defmodule MicrowavepropWeb.RoverPlanningLive do
  @moduledoc """
  `/rover-planning` paginated table of planned rover missions.
  Globally visible, owner-mutable; admins can edit/delete any mission.
  """
  use MicrowavepropWeb, :live_view
  use MicrowavepropWeb.LiveTableResource, schema: Microwaveprop.RoverPlanning.Mission

  alias Microwaveprop.Accounts.User
  alias Microwaveprop.RoverPlanning
  alias Microwaveprop.RoverPlanning.Mission

  def table_options do
    %{sorting: %{default_sort: [inserted_at: :desc]}}
  end

  def fields do
    [
      id: %{label: "ID", hidden: true},
      user_id: %{label: "Owner", hidden: true},
      name: %{label: "Mission", sortable: true, searchable: true, renderer: &name_cell/2},
      band_mhz: %{label: "Bands", sortable: true, renderer: &bands_cell/2},
      only_known_good: %{label: "Scope", sortable: true, renderer: &scope_cell/1},
      inserted_at: %{label: "Created", sortable: true, renderer: &format_ts/1}
    ]
  end

  def filters, do: []

  @impl true
  def mount(_params, _session, socket) do
    {:ok,
     assign(socket,
       page_title: "Rover Planning"
     )}
  end

  @impl true
  def handle_event("delete", %{"id" => id}, socket) do
    case current_user(socket) do
      %User{} = user ->
        case RoverPlanning.delete_mission(user, id) do
          {:ok, _} ->
            {:noreply,
             socket
             |> put_flash(:info, "Mission deleted.")
             |> reload()}

          {:error, :not_found} ->
            {:noreply, put_flash(socket, :error, "You can only delete your own missions.")}
        end

      _ ->
        {:noreply, put_flash(socket, :error, "Sign in required.")}
    end
  end

  defp reload(socket) do
    options = socket.assigns.options
    data_provider = socket.assigns[:data_provider]
    table_options = get_merged_table_options()

    {resources, updated_options} = fetch_resources(options, data_provider)

    socket
    |> assign_to_socket(resources, table_options)
    |> assign(:options, updated_options)
  end

  defp current_user(%Phoenix.LiveView.Socket{assigns: assigns}), do: scope_user(assigns)
  defp current_user(assigns) when is_map(assigns), do: scope_user(assigns)

  defp scope_user(assigns) do
    case assigns[:current_scope] do
      %{user: %User{} = user} -> user
      _ -> nil
    end
  end

  defp can_modify?(scope, %{user_id: user_id}) do
    case scope do
      %{user: %User{is_admin: true}} -> true
      %{user: %User{id: ^user_id}} when not is_nil(user_id) -> true
      _ -> false
    end
  end

  defp can_modify?(_, _), do: false

  defp actions_for(scope) do
    [
      buttons: fn %{record: record} ->
        row_actions(record, scope)
      end
    ]
  end

  defp row_actions(record, scope) do
    assigns = %{record: record, can_modify?: can_modify?(scope, record)}

    ~H"""
    <div class="flex gap-2">
      <.link
        navigate={~p"/rover-planning/#{@record.id}"}
        class="btn btn-xs btn-ghost"
      >
        View
      </.link>
      <.link
        :if={@can_modify?}
        navigate={~p"/rover-planning/#{@record.id}/edit"}
        class="btn btn-xs btn-ghost"
      >
        Edit
      </.link>
      <button
        :if={@can_modify?}
        type="button"
        phx-click="delete"
        phx-value-id={@record.id}
        data-confirm="Delete this mission?"
        class="btn btn-xs btn-ghost text-error"
      >
        Delete
      </button>
    </div>
    """
  end

  defp name_cell(value, %{id: id}) do
    assigns = %{id: id, name: value || "(unnamed)"}

    ~H"""
    <.link navigate={~p"/rover-planning/#{@id}"} class="font-semibold hover:underline">
      {@name}
    </.link>
    """
  end

  # Renders the full bands list (multi-band missions can have several;
  # the bound column is `band_mhz` so the table can still sort by the
  # primary band, but the cell shows every band the matrix scores).
  defp bands_cell(_value, record) do
    case Mission.bands(struct(Mission, Map.take(record, [:band_mhz, :bands_mhz]))) do
      [] -> "—"
      [single] -> band_label(single)
      list -> Enum.map_join(list, " · ", &band_label/1)
    end
  end

  defp band_label(mhz) when is_integer(mhz) and mhz >= 1000 do
    ghz = mhz / 1000
    label = if ghz == trunc(ghz), do: "#{trunc(ghz)}", else: Float.to_string(Float.round(ghz, 1))
    "#{label} GHz"
  end

  defp band_label(mhz) when is_integer(mhz), do: "#{mhz} MHz"
  defp band_label(_), do: "—"

  defp scope_cell(true) do
    assigns = %{}
    ~H|<span class="badge badge-success badge-sm">Known good only</span>|
  end

  defp scope_cell(false) do
    assigns = %{}
    ~H|<span class="badge badge-info badge-sm">All locations</span>|
  end

  defp scope_cell(_), do: ""

  defp format_ts(nil), do: ""
  defp format_ts(%DateTime{} = dt), do: Calendar.strftime(dt, "%Y-%m-%d")
  defp format_ts(%NaiveDateTime{} = dt), do: Calendar.strftime(dt, "%Y-%m-%d")
  defp format_ts(other), do: to_string(other)

  @impl true
  def render(assigns) do
    ~H"""
    <Layouts.app flash={@flash} current_scope={@current_scope} max_width="max-w-6xl">
      <.header>
        Rover Planning
        <:subtitle>
          Plan rover missions: enter your stationary stations, pick a band, and
          we compute terrain path profiles from every known-good rover location.
        </:subtitle>
        <:actions>
          <.link
            :if={current_user(assigns)}
            navigate={~p"/rover-planning/new"}
            class="btn btn-primary"
          >
            <.icon name="hero-plus" class="w-5 h-5" /> New mission
          </.link>
        </:actions>
      </.header>

      <p :if={is_nil(current_user(assigns))} class="alert alert-info text-sm mb-4">
        <a href={~p"/users/log-in"} class="link link-primary">Sign in</a> to plan a mission.
      </p>

      <.live_table
        fields={fields()}
        filters={filters()}
        options={@options}
        streams={@streams}
        actions={actions_for(@current_scope)}
      />
    </Layouts.app>
    """
  end
end
