defmodule SimpleshopTheme.Theme.Fonts do
  @moduledoc """
  Centralized font configuration for the theme system.

  This module defines all available fonts and their variants, maps typography
  presets to font pairs, and generates CSS @font-face declarations.

  Font files are expected to be in /priv/static/fonts/ and served at /fonts/.
  """

  # Font definitions: family name, file prefix, and available weights
  @fonts %{
    inter: %{
      family: "Inter",
      file_prefix: "inter-v20-latin",
      weights: [300, 400, 500, 600, 700],
      fallback: "system-ui, sans-serif"
    },
    manrope: %{
      family: "Manrope",
      file_prefix: "manrope-v20-latin",
      weights: [400, 500, 600, 700],
      fallback: "system-ui, sans-serif"
    },
    raleway: %{
      family: "Raleway",
      file_prefix: "raleway-v37-latin",
      weights: [300, 400, 500],
      fallback: "system-ui, sans-serif"
    },
    playfair: %{
      family: "Playfair Display",
      file_prefix: "playfair-display-v40-latin",
      weights: [400, 500, 700],
      fallback: "Georgia, serif"
    },
    space_grotesk: %{
      family: "Space Grotesk",
      file_prefix: "space-grotesk-v22-latin",
      weights: [400, 500, 600],
      fallback: "system-ui, sans-serif"
    },
    cormorant: %{
      family: "Cormorant Garamond",
      file_prefix: "cormorant-garamond-v21-latin",
      weights: [400, 500, 600],
      fallback: "Georgia, serif"
    },
    source_serif: %{
      family: "Source Serif 4",
      file_prefix: "source-serif-4-v14-latin",
      weights: [400, 600],
      fallback: "Georgia, serif"
    },
    fraunces: %{
      family: "Fraunces",
      file_prefix: "fraunces-v38-latin",
      weights: [400, 500, 600, 700],
      fallback: "Georgia, serif"
    },
    work_sans: %{
      family: "Work Sans",
      file_prefix: "work-sans-v24-latin",
      weights: [300, 400, 500, 600],
      fallback: "system-ui, sans-serif"
    },
    dm_sans: %{
      family: "DM Sans",
      file_prefix: "dm-sans-v17-latin",
      weights: [400, 500, 600, 700],
      fallback: "system-ui, sans-serif"
    }
  }

  # Typography presets map to heading and body font keys
  @typography_fonts %{
    "clean" => %{heading: :manrope, body: :inter},
    "editorial" => %{heading: :playfair, body: :raleway},
    "modern" => %{heading: :space_grotesk, body: :inter},
    "classic" => %{heading: :cormorant, body: :source_serif},
    "friendly" => %{heading: :fraunces, body: :work_sans},
    "minimal" => %{heading: :dm_sans, body: :source_serif},
    "impulse" => %{heading: :raleway, body: :inter}
  }

  @doc """
  Returns the font configuration for a given font key.
  """
  def get_font(key), do: Map.get(@fonts, key)

  @doc """
  Returns all font configurations.
  """
  def all_fonts, do: @fonts

  @doc """
  Returns the heading and body font keys for a typography preset.
  """
  def fonts_for_typography(typography) do
    Map.get(@typography_fonts, typography, @typography_fonts["clean"])
  end

  @doc """
  Returns the CSS font-family declaration (with fallbacks) for a font key.
  """
  def font_family(key) do
    case get_font(key) do
      %{family: family, fallback: fallback} -> "'#{family}', #{fallback}"
      nil -> "system-ui, sans-serif"
    end
  end

  @doc """
  Generates @font-face CSS for a specific typography preset.

  Only includes the fonts needed for that preset.

  Accepts an optional path_resolver function to transform font URLs.
  In production, pass `&SimpleshopThemeWeb.Endpoint.static_path/1` for digested paths.
  """
  def generate_font_faces(typography, path_resolver \\ &default_path_resolver/1) do
    %{heading: heading_key, body: body_key} = fonts_for_typography(typography)

    font_keys =
      if heading_key == body_key do
        [heading_key]
      else
        [heading_key, body_key]
      end

    Enum.map_join(font_keys, "\n", &generate_font_face_for_font(&1, path_resolver))
  end

  @doc """
  Generates @font-face CSS for ALL fonts.

  Used in the theme editor where users can switch between typography presets.

  Accepts an optional path_resolver function for digested paths.
  """
  def generate_all_font_faces(path_resolver \\ &default_path_resolver/1) do
    @fonts
    |> Map.keys()
    |> Enum.map_join("\n", &generate_font_face_for_font(&1, path_resolver))
  end

  @doc """
  Returns the font file paths (without /fonts prefix) for a typography preset.

  Used by templates to generate preload links with digested paths via ~p sigil.
  """
  def preload_font_paths(typography) do
    %{heading: heading_key, body: body_key} = fonts_for_typography(typography)

    # Preload the most commonly used weights
    preload_weights = %{
      # For headings, preload the typical heading weight (500-600)
      heading: [500, 600],
      # For body, preload regular and semibold
      body: [400, 600]
    }

    heading_paths = font_paths_for_weights(heading_key, preload_weights.heading)
    body_paths = font_paths_for_weights(body_key, preload_weights.body)

    # Deduplicate in case heading and body use the same font
    (heading_paths ++ body_paths) |> Enum.uniq()
  end

  defp font_paths_for_weights(key, weights) do
    case get_font(key) do
      %{file_prefix: prefix, weights: available_weights} ->
        weights
        |> Enum.filter(&(&1 in available_weights))
        |> Enum.map(fn weight ->
          weight_suffix = if weight == 400, do: "regular", else: to_string(weight)
          "#{prefix}-#{weight_suffix}.woff2"
        end)

      nil ->
        []
    end
  end

  @doc """
  Generates preload link tags for a specific typography preset.

  Returns a list of maps with href, as, type, and crossorigin attributes.

  Accepts an optional path_resolver function for digested paths.
  In production, pass `&SimpleshopThemeWeb.Endpoint.static_path/1`.
  """
  def preload_links(typography, path_resolver \\ &default_path_resolver/1) do
    typography
    |> preload_font_paths()
    |> Enum.map(fn filename ->
      %{
        href: path_resolver.("/fonts/#{filename}"),
        as: "font",
        type: "font/woff2",
        crossorigin: true
      }
    end)
  end

  # Private functions

  defp default_path_resolver(path), do: path

  defp generate_font_face_for_font(key, path_resolver) do
    case get_font(key) do
      %{family: family, file_prefix: prefix, weights: weights} ->
        Enum.map_join(weights, "", fn weight ->
          weight_suffix = if weight == 400, do: "regular", else: to_string(weight)
          font_path = path_resolver.("/fonts/#{prefix}-#{weight_suffix}.woff2")

          """
          @font-face {
            font-family: '#{family}';
            font-style: normal;
            font-weight: #{weight};
            font-display: swap;
            src: url('#{font_path}') format('woff2');
          }
          """
        end)

      nil ->
        ""
    end
  end
end
