defmodule Towerops.Profiles.ProfileWatcher do
  @moduledoc """
  Watches YAML profile files for changes and automatically reloads them.

  Uses FileSystem to monitor the priv/profiles directory for file changes.
  When a .yaml or .yml file is created, modified, or deleted, triggers
  a reload of all profiles via YamlProfiles.reload/0.

  Note: Only available in development mode. FileSystem is a dev-only dependency.
  """
  use GenServer

  alias Towerops.Profiles.YamlProfiles

  require Logger

  @profiles_dir "priv/profiles"

  def start_link(opts \\ []) do
    GenServer.start_link(__MODULE__, opts, name: __MODULE__)
  end

  @impl true
  def init(_opts) do
    # Only start file watcher in development
    # FileSystem is a dev-only dependency
    if Code.ensure_loaded?(FileSystem) do
      # Get the absolute path to the profiles directory
      profiles_path = Path.join(Application.app_dir(:towerops), @profiles_dir)

      # Start watching the profiles directory for changes (using apply to avoid compile-time warnings)
      {:ok, watcher_pid} = apply(FileSystem, :start_link, [[dirs: [profiles_path]]])
      apply(FileSystem, :subscribe, [watcher_pid])

      Logger.info("ProfileWatcher: Started watching #{profiles_path}")

      {:ok, %{watcher_pid: watcher_pid, profiles_path: profiles_path}}
    else
      # In production, FileSystem is not available
      Logger.debug("ProfileWatcher: FileSystem not available, running in no-op mode (dev-only feature)")
      {:ok, %{}}
    end
  end

  @impl true
  def handle_info({:file_event, _watcher_pid, {path, events}}, state) do
    # Only reload if it's a YAML file change
    if yaml_file?(path) and should_reload?(events) do
      Logger.info("ProfileWatcher: Detected change in #{Path.relative_to_cwd(path)}, reloading profiles...")

      case YamlProfiles.reload() do
        {:ok, profiles} when is_list(profiles) ->
          Logger.info("ProfileWatcher: Successfully reloaded #{length(profiles)} profiles")

        {:error, reason} ->
          Logger.error("ProfileWatcher: Failed to reload profiles: #{inspect(reason)}")
      end
    end

    {:noreply, state}
  end

  @impl true
  def handle_info({:file_event, _watcher_pid, :stop}, state) do
    Logger.warning("ProfileWatcher: File watcher stopped")
    {:noreply, state}
  end

  # Check if the file is a YAML profile file
  defp yaml_file?(path) do
    String.ends_with?(path, [".yaml", ".yml"])
  end

  # Check if the events indicate we should reload
  # Reload on created, modified, or removed events
  # Don't reload on :undefined or other metadata-only changes
  defp should_reload?(events) when is_list(events) do
    Enum.any?(events, fn event ->
      event in [:created, :modified, :removed, :renamed]
    end)
  end

  defp should_reload?(_), do: false
end
