"""
Tests for ChivesSorting and the <chives-sort-options> web component.
"""

import json
from typing import Any

from playwright.sync_api import expect, Page
import pytest

from chives.browser_fixtures import file_uri


def apply_sorting(
    page: Page,
    *,
    sorting_config_json: str,
    url_query: str,
    default_sort_order: str,
    items: Any,
) -> None:
    """
    Sort a list of items and the sorting controls on the page.
    """
    page.goto("about:blank")

    with open("javascript/chives-sorting.js") as f:
        component_js = f.read()

    page.evaluate(
        """
        %s
        const sortOptions = %s;
        const searchParams = new URLSearchParams(%s);
        const sorting = new ChivesSorting(sortOptions, searchParams);

        const defaultSortOrder = %s;
        if (defaultSortOrder) {
            sorting.defaultSortOrder = defaultSortOrder;
        }

        const items = %s;
        const sortedItems = sorting.apply(items);

        const listOfItems = document.createElement("p");
        listOfItems.innerText = JSON.stringify(sortedItems);
        document.body.appendChild(listOfItems);

        renderSortingControls({
            "querySelector": "body",
            sorting,
            searchParams,
        });
        """
        % (
            component_js,
            sorting_config_json.strip(),
            json.dumps(url_query),
            json.dumps(default_sort_order),
            json.dumps(items),
        )
    )


@pytest.mark.parametrize(
    "url_query, expected_items, default_sort_order, expected_sort_order_key",
    [
        ("", '["apple","banana","coconut","date","elderberry"]', "", "AtoZ"),
        (
            "sortOrder=AtoZ",
            '["apple","banana","coconut","date","elderberry"]',
            "",
            "AtoZ",
        ),
        (
            "sortOrder=ZtoA",
            '["elderberry","date","coconut","banana","apple"]',
            "",
            "ZtoA",
        ),
        # Default sort order is used if URL params don't specify
        ("", '["elderberry","date","coconut","banana","apple"]', "ZtoA", "ZtoA"),
        (
            "sortOrder=length",
            '["date","apple","banana","coconut","elderberry"]',
            "ZtoA",
            "length",
        ),
        # Unrecognised sort order => falls back to the first in the list
        (
            "sortOrder=unknown",
            '["apple","banana","coconut","date","elderberry"]',
            "",
            "AtoZ",
        ),
    ],
)
def test_render_basic_sorting(
    page: Page,
    url_query: str,
    expected_items: str,
    default_sort_order: str,
    expected_sort_order_key: str,
) -> None:
    """
    Test basic sorting order and controls.
    """
    apply_sorting(
        page,
        sorting_config_json="""
            [
                {
                    key: "AtoZ",
                    label: "title (A to Z)",
                    compareFn: (a, b) => a > b ? 1 : -1,
                },
                {
                    key: "ZtoA",
                    label: "title (Z to A)",
                    compareFn: (a, b) => a > b ? -1 : 1,
                },
                {
                    key: "length",
                    label: "length",
                    compareFn: (a, b) => a.length - b.length,
                },
            ]
        """,
        url_query=url_query,
        default_sort_order=default_sort_order,
        items=["apple", "banana", "coconut", "date", "elderberry"],
    )

    items_elem = page.locator("p")
    assert items_elem.inner_text() == expected_items

    sorting_elem = page.locator("chives-sort-options")
    expect(sorting_elem).to_be_visible()
    assert (
        sorting_elem.locator("option[selected]").get_attribute("value")
        == expected_sort_order_key
    )


def test_selecting_a_sort_order_resets_page_number(page: Page) -> None:
    """
    Selecting a sort order resets the page number.
    """
    uri = (
        file_uri("tests/fixtures/html/greeting.html")
        + "?sortOrder=ZtoA&page=2&tag=cats"
    )
    page.goto(uri)

    with open("javascript/chives-sorting.js") as f:
        component_js = f.read()

    page.evaluate(
        """
        %s
        const sortOptions = [
            {key: "AtoZ", label: "title (A to Z)", compareFn: (a, b) => 1},
            {key: "ZtoA", label: "title (Z to A)", compareFn: (a, b) => 1},
        ];
        const searchParams = new URLSearchParams(window.location.search);
        const sorting = new ChivesSorting(sortOptions, searchParams);

        const items = ["apple", "banana", "coconut", "date", "elderberry"];
        const sortedItems = sorting.apply(items);

        renderSortingControls({
            "querySelector": "body",
            sorting,
            searchParams,
        });
        """
        % component_js
    )

    assert page.locator("option").count() == 2

    with page.expect_navigation():
        page.get_by_label("sort by:").select_option("title (A to Z)")

    assert "sortOrder=AtoZ" in page.url
    assert "page=" not in page.url
