defmodule Berrypod.Redirects.LinkScanner do
  @moduledoc """
  Extracts outgoing URLs from page blocks and navigation items.

  Used by the dead link checker to discover all links in site content,
  and by the admin UI to show where a broken URL is used.
  """

  alias Berrypod.{Pages, Site}

  # Block settings keys that contain URLs
  @url_keys ~w(cta_href secondary_cta_href link_href href url)

  @doc """
  Scans all pages and navigation for URLs.

  Returns a list of `%{url: string, type: :internal | :external, sources: [source]}`.
  URLs are deduplicated — each unique URL appears once with all its sources.
  """
  def scan_all do
    page_links = scan_all_pages()
    nav_links = scan_nav()

    (page_links ++ nav_links)
    |> group_by_url()
  end

  @doc """
  Scans a single page's blocks for URLs.

  Returns a list of `%{url: string, type: :internal | :external, sources: [source]}`.
  """
  def scan_page(page) do
    page
    |> extract_page_links()
    |> group_by_url()
  end

  @doc """
  Scans navigation items for URLs.

  Returns a list of `%{url: string, type: :internal | :external, sources: [source]}`.
  """
  def scan_nav do
    header_items = Site.nav_items_for_shop("header")
    footer_items = Site.nav_items_for_shop("footer")

    header_links =
      Enum.flat_map(header_items, fn item ->
        case extract_url(item["href"]) do
          nil -> []
          url -> [%{url: url, type: classify(url), source: nav_source("header", item)}]
        end
      end)

    footer_links =
      Enum.flat_map(footer_items, fn item ->
        case extract_url(item["href"]) do
          nil -> []
          url -> [%{url: url, type: classify(url), source: nav_source("footer", item)}]
        end
      end)

    (header_links ++ footer_links)
    |> group_by_url()
  end

  @doc """
  Finds all sources (pages, nav items) where a specific URL is used.

  Returns a list of `%{type: string, id: string, label: string, edit_path: string}`.
  """
  def find_sources(url) do
    page_sources =
      Pages.list_all_pages()
      |> Enum.flat_map(fn page ->
        blocks = page[:blocks] || []

        blocks
        |> Enum.flat_map(fn block ->
          settings = block["settings"] || %{}

          @url_keys
          |> Enum.filter(fn key -> settings[key] == url end)
          |> Enum.map(fn _key -> page_source(page, block) end)
        end)
      end)

    nav_sources = find_nav_sources(url)

    page_sources ++ nav_sources
  end

  # ── Private ──────────────────────────────────────────────────────

  defp scan_all_pages do
    Pages.list_all_pages()
    |> Enum.flat_map(&extract_page_links/1)
  end

  defp extract_page_links(page) do
    blocks = page[:blocks] || []

    Enum.flat_map(blocks, fn block ->
      settings = block["settings"] || %{}

      @url_keys
      |> Enum.flat_map(fn key ->
        case extract_url(settings[key]) do
          nil -> []
          url -> [%{url: url, type: classify(url), source: page_source(page, block)}]
        end
      end)
    end)
  end

  defp extract_url(nil), do: nil
  defp extract_url(""), do: nil
  defp extract_url("#" <> _), do: nil
  defp extract_url("mailto:" <> _), do: nil
  defp extract_url("tel:" <> _), do: nil
  defp extract_url("{{" <> _), do: nil
  defp extract_url(url) when is_binary(url), do: String.trim(url)
  defp extract_url(_), do: nil

  defp classify("/" <> _), do: :internal
  defp classify("http" <> _), do: :external
  defp classify(_), do: :external

  defp page_source(page, block) do
    block_type = block["type"] || "unknown"
    page_title = page[:title] || page[:slug] || "Unknown"

    %{
      type: "page_block",
      id: to_string(page[:slug]),
      label: "#{page_title} — #{block_type}",
      edit_path: "/admin/pages/#{page[:slug]}"
    }
  end

  defp nav_source(location, item) do
    label = item["label"] || "Unknown"

    %{
      type: "nav_item",
      id: "#{location}_nav",
      label: "#{String.capitalize(location)} nav — #{label}",
      edit_path: "/?edit=site"
    }
  end

  defp find_nav_sources(url) do
    header_items = Site.nav_items_for_shop("header")
    footer_items = Site.nav_items_for_shop("footer")

    header =
      header_items
      |> Enum.filter(&(&1["href"] == url))
      |> Enum.map(&nav_source("header", &1))

    footer =
      footer_items
      |> Enum.filter(&(&1["href"] == url))
      |> Enum.map(&nav_source("footer", &1))

    header ++ footer
  end

  defp group_by_url(links) do
    links
    |> Enum.group_by(& &1.url)
    |> Enum.map(fn {url, entries} ->
      %{
        url: url,
        type: hd(entries).type,
        sources: Enum.map(entries, & &1.source)
      }
    end)
  end
end
