defmodule Berrypod.PaginationTest do
  use Berrypod.DataCase, async: true

  alias Berrypod.Pagination

  describe "page_numbers/1" do
    test "returns all pages when total <= 7" do
      assert Pagination.page_numbers(page(1, 1)) == [1]
      assert Pagination.page_numbers(page(1, 5)) == [1, 2, 3, 4, 5]
      assert Pagination.page_numbers(page(3, 7)) == [1, 2, 3, 4, 5, 6, 7]
    end

    test "shows ellipsis for large page counts" do
      result = Pagination.page_numbers(page(1, 20))
      assert result == [1, 2, :ellipsis, 20]
    end

    test "shows window around current page" do
      result = Pagination.page_numbers(page(10, 20))
      assert result == [1, :ellipsis, 9, 10, 11, :ellipsis, 20]
    end

    test "current page near start" do
      result = Pagination.page_numbers(page(2, 20))
      assert result == [1, 2, 3, :ellipsis, 20]
    end

    test "current page near end" do
      result = Pagination.page_numbers(page(19, 20))
      assert result == [1, :ellipsis, 18, 19, 20]
    end

    test "current page at last" do
      result = Pagination.page_numbers(page(20, 20))
      assert result == [1, :ellipsis, 19, 20]
    end

    test "8 pages with current at 4" do
      result = Pagination.page_numbers(page(4, 8))
      assert result == [1, :ellipsis, 3, 4, 5, :ellipsis, 8]
    end
  end

  describe "showing_text/1" do
    test "returns showing range" do
      assert Pagination.showing_text(page(1, 5, 25, 120)) == "Showing 1\u201325 of 120"
      assert Pagination.showing_text(page(2, 5, 25, 120)) == "Showing 26\u201350 of 120"
      assert Pagination.showing_text(page(5, 5, 25, 120)) == "Showing 101\u2013120 of 120"
    end

    test "returns no results when empty" do
      assert Pagination.showing_text(page(1, 1, 25, 0)) == "No results"
    end
  end

  describe "parse_page/1" do
    test "returns 1 for nil" do
      assert Pagination.parse_page(%{}) == 1
    end

    test "parses valid string" do
      assert Pagination.parse_page(%{"page" => "3"}) == 3
    end

    test "returns 1 for invalid string" do
      assert Pagination.parse_page(%{"page" => "abc"}) == 1
      assert Pagination.parse_page(%{"page" => "0"}) == 1
      assert Pagination.parse_page(%{"page" => "-1"}) == 1
    end

    test "accepts integer values" do
      assert Pagination.parse_page(%{"page" => 5}) == 5
    end

    test "uses custom key" do
      assert Pagination.parse_page(%{"p" => "7"}, "p") == 7
    end
  end

  describe "paginate/2" do
    test "paginates a query" do
      # Create some subscribers as test data
      for i <- 1..7 do
        %Berrypod.Newsletter.Subscriber{}
        |> Berrypod.Newsletter.Subscriber.changeset(%{
          email: "pag#{i}@example.com",
          status: "confirmed",
          confirmed_at: DateTime.utc_now() |> DateTime.truncate(:second),
          consent_text: "test"
        })
        |> Berrypod.Repo.insert!()
      end

      import Ecto.Query

      query =
        from(s in Berrypod.Newsletter.Subscriber,
          order_by: [asc: s.email]
        )

      # Page 1 of 3 (3 per page, 7 total)
      result = Pagination.paginate(query, page: 1, per_page: 3)
      assert length(result.items) == 3
      assert result.page == 1
      assert result.per_page == 3
      assert result.total_count == 7
      assert result.total_pages == 3

      # Page 3 has 1 item
      result = Pagination.paginate(query, page: 3, per_page: 3)
      assert length(result.items) == 1
      assert result.page == 3

      # Page beyond range is clamped
      result = Pagination.paginate(query, page: 99, per_page: 3)
      assert result.page == 3
    end

    test "handles empty result set" do
      import Ecto.Query

      query =
        from(s in Berrypod.Newsletter.Subscriber,
          where: s.email == "nonexistent@nope.com"
        )

      result = Pagination.paginate(query, page: 1, per_page: 25)
      assert result.items == []
      assert result.total_count == 0
      assert result.total_pages == 1
      assert result.page == 1
    end
  end

  # Helpers for building test structs
  defp page(current, total) do
    %Pagination{
      items: [],
      page: current,
      per_page: 25,
      total_count: total * 25,
      total_pages: total
    }
  end

  defp page(current, total_pages, per_page, total_count) do
    %Pagination{
      items: [],
      page: current,
      per_page: per_page,
      total_count: total_count,
      total_pages: total_pages
    }
  end
end
