defmodule AprsmeWeb.WeatherUnits do
  @moduledoc """
  Handles weather unit conversions and formatting based on locale.
  Supports imperial (US) and metric (international) units.
  """

  alias Aprsme.Convert

  @doc """
  Determines the unit system based on locale.
  Returns :imperial for US, :metric for most other countries.
  """
  @spec unit_system(String.t() | nil | any()) :: :imperial | :metric
  def unit_system("en"), do: :imperial
  def unit_system("es"), do: :metric
  def unit_system("de"), do: :metric
  def unit_system("fr"), do: :metric
  def unit_system(locale) when is_binary(locale), do: :metric
  def unit_system(nil), do: :imperial
  def unit_system(_), do: :imperial

  @doc """
  Converts temperature from Fahrenheit to Celsius if needed.
  Returns the temperature in the appropriate unit for the locale.
  """
  @spec format_temperature(number() | any(), String.t()) :: {number() | any(), String.t()}
  def format_temperature(temp, locale) when is_number(temp),
    do: format_by_unit(temp, locale, &Convert.f_to_c/1, "°F", "°C")

  def format_temperature(temp, _locale), do: {temp, "°F"}

  @doc """
  Converts wind speed from mph to km/h if needed.
  Returns the wind speed in the appropriate unit for the locale.
  """
  @spec format_wind_speed(number() | any(), String.t()) :: {number() | any(), String.t()}
  def format_wind_speed(speed, locale) when is_number(speed),
    do: format_by_unit(speed, locale, &Convert.mph_to_kph/1, "mph", "km/h")

  def format_wind_speed(speed, _locale), do: {speed, "mph"}

  @doc """
  Converts rain from inches to mm if needed.
  Returns the rain amount in the appropriate unit for the locale.
  """
  @spec format_rain(number() | any(), String.t()) :: {number() | any(), String.t()}
  def format_rain(rain, locale) when is_number(rain),
    do: format_by_unit(rain, locale, &Convert.inches_to_mm/1, "in", "mm")

  def format_rain(rain, _locale), do: {rain, "in"}

  @doc """
  Formats pressure (keeps hPa for all locales as it's standard).
  """
  @spec format_pressure(number() | any(), any()) :: {number() | any(), String.t()}
  def format_pressure(pressure, _locale), do: {pressure, "hPa"}

  @doc """
  Gets the appropriate unit labels for the locale.
  """
  @spec unit_labels(String.t()) :: %{
          temperature: String.t(),
          wind_speed: String.t(),
          rain: String.t(),
          pressure: String.t()
        }
  def unit_labels(locale), do: do_unit_labels(unit_system(locale))

  defp do_unit_labels(:imperial) do
    %{
      temperature: "°F",
      wind_speed: "mph",
      rain: "in",
      pressure: "hPa"
    }
  end

  defp do_unit_labels(:metric) do
    %{
      temperature: "°C",
      wind_speed: "km/h",
      rain: "mm",
      pressure: "hPa"
    }
  end

  defp format_by_unit(value, locale, converter, imperial_unit, metric_unit) do
    case unit_system(locale) do
      :imperial -> {value, imperial_unit}
      :metric -> {converter.(value), metric_unit}
    end
  end
end
