from datasette.app import Datasette, Database
from datasette.utils import resolve_routes
import pytest
import pytest_asyncio


@pytest.fixture(scope="session")
def routes():
    ds = Datasette()
    return ds._routes()


@pytest.mark.parametrize(
    "path,expected_name,expected_matches",
    (
        ("/", "IndexView", {"format": None}),
        ("/foo", "DatabaseView", {"format": None, "database": "foo"}),
        ("/foo.csv", "DatabaseView", {"format": "csv", "database": "foo"}),
        ("/foo.json", "DatabaseView", {"format": "json", "database": "foo"}),
        ("/foo.humbug", "DatabaseView", {"format": "humbug", "database": "foo"}),
        (
            "/foo/humbug",
            "table_view",
            {"database": "foo", "table": "humbug", "format": None},
        ),
        (
            "/foo/humbug.json",
            "table_view",
            {"database": "foo", "table": "humbug", "format": "json"},
        ),
        (
            "/foo/humbug.blah",
            "table_view",
            {"database": "foo", "table": "humbug", "format": "blah"},
        ),
        (
            "/foo/humbug/1",
            "RowView",
            {"format": None, "database": "foo", "pks": "1", "table": "humbug"},
        ),
        (
            "/foo/humbug/1.json",
            "RowView",
            {"format": "json", "database": "foo", "pks": "1", "table": "humbug"},
        ),
    ),
)
def test_routes(routes, path, expected_name, expected_matches):
    match, view = resolve_routes(routes, path)
    if expected_name is None:
        assert match is None
    else:
        assert (
            view.__name__ == expected_name or view.view_class.__name__ == expected_name
        )
        assert match.groupdict() == expected_matches


@pytest_asyncio.fixture
async def ds_with_route():
    ds = Datasette()
    await ds.invoke_startup()
    ds.remove_database("_memory")
    db = Database(ds, is_memory=True, memory_name="route-name-db")
    ds.add_database(db, name="original-name", route="custom-route-name")
    await db.execute_write_script(
        """
        create table if not exists t (id integer primary key);
        insert or replace into t (id) values (1);
    """
    )
    return ds


@pytest.mark.asyncio
async def test_db_with_route_databases(ds_with_route):
    response = await ds_with_route.client.get("/-/databases.json")
    assert response.json()[0] == {
        "name": "original-name",
        "route": "custom-route-name",
        "path": None,
        "size": 0,
        "is_mutable": True,
        "is_memory": True,
        "hash": None,
    }


@pytest.mark.asyncio
@pytest.mark.parametrize(
    "path,expected_status",
    (
        ("/", 200),
        ("/original-name", 404),
        ("/original-name/t", 404),
        ("/original-name/t/1", 404),
        ("/custom-route-name", 200),
        ("/custom-route-name/-/query?sql=select+id+from+t", 200),
        ("/custom-route-name/t", 200),
        ("/custom-route-name/t/1", 200),
    ),
)
async def test_db_with_route_that_does_not_match_name(
    ds_with_route, path, expected_status
):
    response = await ds_with_route.client.get(path)
    assert response.status_code == expected_status
    # There should be links to custom-route-name but none to original-name
    if response.status_code == 200:
        assert "/custom-route-name" in response.text
        assert "/original-name" not in response.text
