defmodule AprsmeWeb.MapLive.PacketUtils do
  @moduledoc """
  Map-specific packet utilities. Provides weather-check queries against the
  database and a convenience wrapper for weather field display.

  For general packet field access, symbol info, timestamps, callsign
  generation, and weather-packet detection, use
  `AprsmeWeb.Live.Shared.PacketUtils` directly.

  For building marker/popup data, use `AprsmeWeb.MapLive.DataBuilder` directly.
  """

  import Ecto.Query

  alias AprsmeWeb.Live.Shared.PacketUtils, as: SharedPacketUtils
  alias AprsmeWeb.MapLive.DataBuilder

  @doc """
  Checks if a station has sent weather packets by looking at recent packets.
  """
  @spec has_weather_packets?(String.t()) :: boolean()
  def has_weather_packets?(callsign) when is_binary(callsign) do
    query = build_weather_check_query(callsign)
    Aprsme.Repo.exists?(query)
  rescue
    _ -> false
  end

  def has_weather_packets?(_), do: false

  @doc """
  Recursively converts tuples in data structures to strings for JSON serialization.
  """
  @spec convert_tuples_to_strings(any()) :: any()
  def convert_tuples_to_strings(map) when is_map(map) do
    if Map.has_key?(map, :__struct__) do
      map
    else
      Map.new(map, fn {k, v} ->
        {k, convert_tuples_to_strings(v)}
      end)
    end
  end

  def convert_tuples_to_strings(list) when is_list(list) do
    Enum.map(list, &convert_tuples_to_strings/1)
  end

  def convert_tuples_to_strings(tuple) when is_tuple(tuple) do
    to_string(inspect(tuple))
  end

  def convert_tuples_to_strings(other), do: other

  @doc """
  Extracts weather field data with "N/A" fallback for display.
  """
  @spec get_weather_field(map(), atom()) :: String.t()
  def get_weather_field(packet, key) do
    case SharedPacketUtils.get_weather_field(packet, key) do
      nil -> "N/A"
      value -> value
    end
  end

  # Keep build_packet_data delegations for backward compatibility with tests
  defdelegate build_packet_data(packet, is_most_recent_for_callsign, locale), to: DataBuilder
  defdelegate build_packet_data(packet, is_most_recent_for_callsign), to: DataBuilder
  defdelegate build_packet_data(packet), to: DataBuilder

  defp build_weather_check_query(callsign) do
    from p in Aprsme.Packet,
      where: p.sender == ^callsign,
      where:
        fragment(
          "? IS NOT NULL OR ? IS NOT NULL OR ? IS NOT NULL OR ? IS NOT NULL OR ? IS NOT NULL OR ? IS NOT NULL OR ? IS NOT NULL OR ? IS NOT NULL OR ? IS NOT NULL OR ?->>'luminosity' IS NOT NULL OR ?->>'rain_midnight' IS NOT NULL",
          p.temperature,
          p.humidity,
          p.pressure,
          p.wind_direction,
          p.wind_speed,
          p.wind_gust,
          p.rain_1h,
          p.rain_24h,
          p.snow,
          p.data,
          p.data
        ),
      select: fragment("1"),
      limit: 1
  end
end
