defmodule Pinchflat.Metadata.MetadataParser do
  @moduledoc """
  yt-dlp offers a LOT of metadata in its JSON response, some of which
  needs to be extracted and included in various models.

  For now, also squirrel all of it away in the `media_metadata` table.
  I might revisit this or pare it down later, but I'd rather need it
  and not have it, ya know?
  """

  alias Pinchflat.YtDlp.Media, as: YtDlpMedia

  @doc """
  Parses the given JSON response from yt-dlp and returns a map of
  the needful media_item attributes, along with anything needed for
  its associations.

  Returns map()
  """
  def parse_for_media_item(metadata) do
    Map.new()
    |> Map.merge(parse_media_metadata(metadata))
    |> Map.merge(parse_subtitle_metadata(metadata))
    |> Map.merge(parse_thumbnail_metadata(metadata))
    |> Map.merge(parse_infojson_metadata(metadata))
  end

  defp parse_media_metadata(metadata) do
    Map.merge(
      Map.from_struct(YtDlpMedia.response_to_struct(metadata)),
      %{
        media_filepath: metadata["filepath"]
      }
    )
  end

  defp parse_subtitle_metadata(metadata) do
    subtitle_filepaths =
      (metadata["requested_subtitles"] || %{})
      |> Enum.map(fn {lang, attrs} -> [lang, attrs["filepath"]] end)
      |> Enum.sort(fn [lang_a, _], [lang_b, _] -> lang_a < lang_b end)

    %{
      subtitle_filepaths: subtitle_filepaths
    }
  end

  defp parse_thumbnail_metadata(metadata) do
    thumbnail_filepath =
      (metadata["thumbnails"] || %{})
      # Reverse so that higher resolution thumbnails come first.
      # This _shouldn't_ matter yet, but I'd rather default to the best
      # in case I'm wrong.
      |> Enum.reverse()
      |> Enum.find_value(fn attrs -> attrs["filepath"] end)

    if thumbnail_filepath do
      # NOTE: whole ordeal needed due to a bug I found in yt-dlp
      # https://github.com/yt-dlp/yt-dlp/issues/9445
      # Can be reverted to remove this entire conditional once fixed
      filepath =
        thumbnail_filepath
        |> String.split(~r{\.}, include_captures: true)
        |> List.insert_at(-3, "-thumb")
        |> Enum.join()

      %{
        thumbnail_filepath: filepath_if_exists(filepath)
      }
    else
      %{
        thumbnail_filepath: nil
      }
    end
  end

  defp parse_infojson_metadata(metadata) do
    %{
      metadata_filepath: filepath_if_exists(metadata["infojson_filename"])
    }
  end

  # NOTE: this should not be needed, but it is due to a bug in yt-dlp.
  # Can remove once this is resolved:
  # https://github.com/yt-dlp/yt-dlp/issues/9445#issuecomment-2018724344
  defp filepath_if_exists(nil), do: nil

  defp filepath_if_exists(filepath) do
    if File.exists?(filepath) do
      filepath
    else
      nil
    end
  end
end
