defmodule Raxol.Core.I18n do
  @moduledoc """
  Refactored internationalization module using GenServer for state management.

  This module provides the same API as the original I18n module but delegates
  all state management to a supervised GenServer, eliminating Process dictionary usage.

  ## Migration Guide

  1. Add the I18n.I18nServer to your supervision tree:

      children = [
        {Raxol.Core.I18n.I18nServer, name: Raxol.Core.I18n.I18nServer, config: config}
      ]
      
  2. Replace `Raxol.Core.I18n` with `Raxol.Core.I18n` in your code

  3. All API calls remain the same
  """

  alias Raxol.Core.I18n.I18nServer

  @server Raxol.Core.I18n.I18nServer

  @doc """
  Initialize the i18n framework.

  Now initializes the GenServer state instead of Process dictionary.
  """
  def init(config \\ []) do
    # Normalize config to map - handle both keyword lists and maps
    config_map =
      cond do
        is_map(config) -> config
        is_list(config) and Keyword.keyword?(config) -> Enum.into(config, %{})
        is_list(config) and config == [] -> %{}
        true -> config
      end

    ensure_server_started(config_map)
    I18nServer.init_i18n(@server, config_map)
  end

  @doc """
  Get a translated string for the given key.

  ## Examples

      iex> I18n.t("welcome_message")
      "Welcome!"
      
      iex> I18n.t("hello_name", %{name: "John"})
      "Hello, John!"
  """
  def t(key, bindings \\ %{}) do
    ensure_server_started()
    I18nServer.t(@server, key, bindings)
  end

  @doc """
  Set the current locale.

  ## Examples

      iex> I18n.set_locale("fr")
      :ok
      
      iex> I18n.set_locale("invalid")
      {:error, :locale_not_available}
  """
  def set_locale(locale) do
    ensure_server_started()
    I18nServer.set_locale(@server, locale)
  end

  @doc """
  Get the current locale.

  ## Examples

      iex> I18n.get_locale()
      "en"
  """
  def get_locale do
    ensure_server_started()
    I18nServer.get_locale(@server)
  end

  @doc """
  Check if the current locale is right-to-left.

  ## Examples

      iex> I18n.set_locale("ar")
      iex> I18n.rtl?()
      true
      
      iex> I18n.set_locale("en")
      iex> I18n.rtl?()
      false
  """
  def rtl? do
    ensure_server_started()
    I18nServer.rtl?(@server)
  end

  @doc """
  Format a currency amount according to the current locale.

  ## Examples

      iex> I18n.format_currency(1234.56, "USD")
      "$1,234.56"
      
      iex> I18n.set_locale("fr")
      iex> I18n.format_currency(1234.56, "EUR")
      "1 234,56 €"
  """
  def format_currency(amount, currency_code)
      when is_number(amount) and is_binary(currency_code) do
    ensure_server_started()
    I18nServer.format_currency(@server, amount, currency_code)
  end

  @doc """
  Format a datetime according to the current locale.

  ## Examples

      iex> dt = DateTime.utc_now()
      iex> I18n.format_datetime(dt)
      "December 12, 2025 at 3:45 PM"
  """
  def format_datetime(datetime) when is_struct(datetime, DateTime) do
    ensure_server_started()
    I18nServer.format_datetime(@server, datetime)
  end

  @doc """
  Handle locale changed events.

  This is now handled internally by the server.
  """
  def handle_locale_changed({:locale_changed, _old, _new} = event) do
    # The server handles this internally now
    # This function exists for backward compatibility
    _ = event
    :ok
  end

  @doc """
  Clean up i18n resources.

  With GenServer, cleanup happens automatically when the server stops.
  """
  def cleanup do
    case Process.whereis(@server) do
      nil ->
        :ok

      pid ->
        # Use try/catch because the process might be stopped between
        # the whereis check and the stop call
        try do
          GenServer.stop(pid, :normal, 5000)
        catch
          :exit, {:noproc, _} -> :ok
          :exit, {:normal, _} -> :ok
        end

        :ok
    end
  end

  @doc """
  Get all available locales.
  """
  def available_locales do
    ensure_server_started()
    I18nServer.available_locales(@server)
  end

  @doc """
  Add or update translations for a locale.

  ## Examples

      iex> I18n.add_translations("en", %{
      ...>   "new_key" => "New translation",
      ...>   "another_key" => "Another translation"
      ...> })
      :ok
  """
  def add_translations(locale, translations) when is_map(translations) do
    ensure_server_started()
    I18nServer.add_translations(@server, locale, translations)
  end

  # Private Functions

  @spec ensure_server_started(map()) :: any()
  defp ensure_server_started(config \\ %{}) do
    case Process.whereis(@server) do
      nil ->
        # Start the server if not running
        {:ok, _pid} = I18nServer.start_link(name: @server, config: config)
        :ok

      _pid ->
        :ok
    end
  end
end
