defmodule Raxol.Animation.Adaptation do
  @moduledoc """
  Handles animation adaptation based on user preferences and accessibility settings.

  This module is responsible for:
  - Re-adapting animations when user preferences change
  - Managing animation adaptation for accessibility
  - Handling preference change notifications
  """

  alias Raxol.Animation.Accessibility, as: AnimAccessibility
  alias Raxol.Animation.Lifecycle
  alias Raxol.Animation.StateManager, as: StateManager

  require Raxol.Core.Runtime.Log

  @doc """
  Re-adapt existing animations if settings have changed.

  This function checks if user preferences have changed and re-adapts all active animations accordingly.
  Returns a list of animations that were completed due to being disabled.
  """
  def re_adapt_animations_if_needed(
        user_preferences_pid,
        active_animations \\ nil
      ) do
    active_animations =
      active_animations || StateManager.get_active_animations()

    Raxol.Core.Runtime.Log.debug(
      "[Animation] Re-adapting #{map_size(active_animations)} active animations"
    )

    # Fetch current preferences
    current_reduced_motion =
      Raxol.Core.UserPreferences.get(
        [:accessibility, :reduced_motion],
        user_preferences_pid
      ) || false

    current_cognitive_accessibility =
      Raxol.Core.UserPreferences.get(
        [:accessibility, :cognitive_accessibility],
        user_preferences_pid
      ) || false

    # Update StateManager settings
    settings = StateManager.get_settings()

    new_settings = %{
      settings
      | reduced_motion: current_reduced_motion,
        cognitive_accessibility: current_cognitive_accessibility
    }

    StateManager.init(new_settings)

    # Now re-fetch settings for use below
    settings = StateManager.get_settings()
    reduce_motion? = Map.get(settings, :reduced_motion, false)

    cognitive_accessibility? =
      Map.get(settings, :cognitive_accessibility, false)

    completed_due_to_disable =
      Enum.flat_map(active_animations, fn {element_id, element_animations} ->
        Enum.flat_map(element_animations, fn {animation_name, instance} ->
          animation = instance.animation

          # Re-adapt the animation
          adapted_animation =
            AnimAccessibility.adapt_animation(
              animation,
              reduce_motion?,
              cognitive_accessibility?
            )

          # Update the instance with the adapted animation
          updated_instance = Map.put(instance, :animation, adapted_animation)

          # Handle disabled animations properly
          case AnimAccessibility.disabled?(adapted_animation) do
            true ->
              # For disabled animations, mark as pending completion and ensure they complete quickly
              updated_instance =
                Map.put(updated_instance, :pending_completion, true)

              # Immediately send completion message for disabled animations
              Lifecycle.handle_animation_completion(
                adapted_animation,
                element_id,
                animation_name,
                updated_instance,
                user_preferences_pid
              )

              # Return as completed due to disable
              [{element_id, animation_name, updated_instance}]

            false ->
              # For enabled animations, remove pending_completion flag if it was set
              _updated_instance =
                Map.delete(updated_instance, :pending_completion)

              # Not completed
              []
          end

          # Update the instance in the state manager
          StateManager.put_active_animation(
            element_id,
            animation_name,
            updated_instance
          )

          []
        end)
      end)

    completed_due_to_disable
  end

  @doc """
  Check if animations should be reduced due to user preferences.
  """
  def should_reduce_motion?(user_preferences_pid \\ nil) do
    Raxol.Core.UserPreferences.get(
      [:accessibility, :reduced_motion],
      user_preferences_pid
    ) || false
  end

  @doc """
  Check if cognitive accessibility should be applied.
  """
  def should_apply_cognitive_accessibility? do
    Raxol.Core.UserPreferences.get([:accessibility, :cognitive_accessibility]) ||
      false
  end
end
