import sys
from pathlib import Path

from clarabot_nano_common.indexer.utility import (
    create_accessor_path,
    create_docs_query_children,
    create_docs_query_exact,
    create_docs_query_tree,
    create_doc_query_path,
    convert_accessor_to_path,
    convert_accessor_to_parent_accessor,
)


def test_indexer_utility_create_accessor_path_0():
    for root, rel, path in [
        ("/", "", "/"),
        ("/", "a", "//a"),
        ("/", "a/b", "//a/b"),
        ("/x", "", "/x/"),
        ("/x", "a", "/x//a"),
        ("/x", "a/b", "/x//a/b"),
        ("//?/c:/", "", "//?/c:/"),
        ("//?/c:/", "a", "//?/c://a"),
        ("//?/c:/", "a/b", "//?/c://a/b"),
        ("//?/c:/x", "", "//?/c:/x/"),
        ("//?/c:/x", "a", "//?/c:/x//a"),
        ("//?/c:/x", "a/b", "//?/c:/x//a/b"),
        ("//localhost/c$/", "", "//localhost/c$/"),
        ("//localhost/c$/", "a", "//localhost/c$//a"),
        ("//localhost/c$/", "a/b", "//localhost/c$//a/b"),
        ("//localhost/c$/x", "", "//localhost/c$/x/"),
        ("//localhost/c$/x", "a", "//localhost/c$/x//a"),
        ("//localhost/c$/x", "a/b", "//localhost/c$/x//a/b"),
        ("//?/UNC/localHost/c$/", "", "//?/UNC/localHost/c$/"),
        ("//?/UNC/localHost/c$/", "a", "//?/UNC/localHost/c$//a"),
        ("//?/UNC/localHost/c$/", "a/b", "//?/UNC/localHost/c$//a/b"),
        ("//?/UNC/localHost/c$/x", "", "//?/UNC/localHost/c$/x/"),
        ("//?/UNC/localHost/c$/x", "a", "//?/UNC/localHost/c$/x//a"),
        ("//?/UNC/localHost/c$/x", "a/b", "//?/UNC/localHost/c$/x//a/b"),
    ]:
        assert create_accessor_path(root, rel) == path
    # NOTE: empty root is not valid for use but raise no errors
    for root, rel, path in [
        ("", "a", "//a"),
        ("", "/", "///"),
    ]:
        assert create_accessor_path(root, rel) == path


def test_indexer_utility_create_accessor_path_1():
    for root, rel_parts, path in [
        ("/", (), "/"),
        ("/", ("a/b",), "//a/b"),
        ("/", ("a/b", "c/d"), "//a/b/c/d"),
        ("/", ("", "c/d"), "//c/d"),
        ("/x", (), "/x/"),
        ("/x", ("a/b",), "/x//a/b"),
        ("/x", ("a/b", "c/d"), "/x//a/b/c/d"),
        ("/x", ("", "c/d"), "/x//c/d"),
        ("//?/c:/", (), "//?/c:/"),
        ("//?/c:/", ("a/b",), "//?/c://a/b"),
        ("//?/c:/", ("a/b", "c/d"), "//?/c://a/b/c/d"),
        ("//?/c:/", ("", "c/d"), "//?/c://c/d"),
        ("//?/c:/x", (), "//?/c:/x/"),
        ("//?/c:/x", ("a/b",), "//?/c:/x//a/b"),
        ("//?/c:/x", ("a/b", "c/d"), "//?/c:/x//a/b/c/d"),
        ("//?/c:/x", ("", "c/d"), "//?/c:/x//c/d"),
        ("//localhost/c$/", (), "//localhost/c$/"),
        ("//localhost/c$/", ("a/b",), "//localhost/c$//a/b"),
        ("//localhost/c$/", ("a/b", "c/d"), "//localhost/c$//a/b/c/d"),
        ("//localhost/c$/", ("", "c/d"), "//localhost/c$//c/d"),
        ("//localhost/c$/x", (), "//localhost/c$/x/"),
        ("//localhost/c$/x", ("a/b",), "//localhost/c$/x//a/b"),
        ("//localhost/c$/x", ("a/b", "c/d"), "//localhost/c$/x//a/b/c/d"),
        ("//localhost/c$/x", ("", "c/d"), "//localhost/c$/x//c/d"),
        ("//?/UNC/localhost/c$/", (), "//?/UNC/localhost/c$/"),
        ("//?/UNC/localhost/c$/", ("a/b",), "//?/UNC/localhost/c$//a/b"),
        ("//?/UNC/localhost/c$/", ("a/b", "c/d"), "//?/UNC/localhost/c$//a/b/c/d"),
        ("//?/UNC/localhost/c$/", ("", "c/d"), "//?/UNC/localhost/c$//c/d"),
        ("//?/UNC/localhost/c$/x", (), "//?/UNC/localhost/c$/x/"),
        ("//?/UNC/localhost/c$/x", ("a/b",), "//?/UNC/localhost/c$/x//a/b"),
        ("//?/UNC/localhost/c$/x", ("a/b", "c/d"), "//?/UNC/localhost/c$/x//a/b/c/d"),
        ("//?/UNC/localhost/c$/x", ("", "c/d"), "//?/UNC/localhost/c$/x//c/d"),
    ]:
        assert create_accessor_path(root, *rel_parts) == path


def test_indexer_utility_create_accessor_path_2():
    rps = [
        ("/", "//"),
        ("/x", "/x//"),
        ("//?/c:/", "//?/c://"),
        ("//?/c:/x", "//?/c:/x//"),
        ("//localhost/c$/", "//localhost/c$//"),
        ("//localhost/c$/x", "//localhost/c$/x//"),
        ("//?/UNC/localhost/c$/", "//?/UNC/localhost/c$//"),
        ("//?/UNC/localhost/c$/x", "//?/UNC/localhost/c$/x//"),
    ]
    for root, path in rps:
        # Use case relevant for simple filtering by root-path prefix of document accessors. (1)
        assert create_accessor_path(root) + "/" == path
        # Use case relevant for drive-path recovery and filtering by root-path of document accessors. (2)
        root_stripped = root.rstrip("/")
        r, _, p = path.rpartition("//")
        assert r == root_stripped
        assert p == ""
        for r2, p2 in rps:
            if r2 == root:
                continue
            assert p2.rpartition("//")[0] != root_stripped


def test_indexer_utility_create_docs_query_children():
    for root, rel, query in [
        ("/", "", 'parents:"/"'),
        ("/", "a/b", 'parents:"//a/b"'),
        ("/x", "", 'parents:"/x/"'),
        ("/x", "a/b", 'parents:"/x//a/b"'),
        ("//?/c:/", "", 'parents:"//?/c:/"'),
        ("//?/c:/", "a/b", 'parents:"//?/c://a/b"'),
        ("//?/c:/x", "", 'parents:"//?/c:/x/"'),
        ("//?/c:/x", "a/b", 'parents:"//?/c:/x//a/b"'),
        ("//localhost/c$/", "", 'parents:"//localhost/c$/"'),
        ("//localhost/c$/", "a/b", 'parents:"//localhost/c$//a/b"'),
        ("//localhost/c$/x", "", 'parents:"//localhost/c$/x/"'),
        ("//localhost/c$/x", "a/b", 'parents:"//localhost/c$/x//a/b"'),
        ("//?/UNC/localhost/c$/", "", 'parents:"//?/UNC/localhost/c$/"'),
        ("//?/UNC/localhost/c$/", "a/b", 'parents:"//?/UNC/localhost/c$//a/b"'),
        ("//?/UNC/localhost/c$/x", "", 'parents:"//?/UNC/localhost/c$/x/"'),
        ("//?/UNC/localhost/c$/x", "a/b", 'parents:"//?/UNC/localhost/c$/x//a/b"'),
    ]:
        assert create_docs_query_children(create_accessor_path(root, rel)) == query
    # check escaping
    assert create_docs_query_children('//a/b"\\"\\x') == 'parents:"//a/b\\"\\\\\\"\\\\x"'


def test_indexer_utility_create_docs_query_exact():
    name = "z"
    for root, rel, query in [
        ("/", "", 'parents:"/" AND accessors:"//z"'),
        ("/", "a/b", 'parents:"//a/b" AND accessors:"//a/b/z"'),
        ("/x", "", 'parents:"/x/" AND accessors:"/x//z"'),
        ("/x", "a/b", 'parents:"/x//a/b" AND accessors:"/x//a/b/z"'),
        ("//?/c:/", "", 'parents:"//?/c:/" AND accessors:"//?/c://z"'),
        ("//?/c:/", "a/b", 'parents:"//?/c://a/b" AND accessors:"//?/c://a/b/z"'),
        ("//?/c:/x", "", 'parents:"//?/c:/x/" AND accessors:"//?/c:/x//z"'),
        ("//?/c:/x", "a/b", 'parents:"//?/c:/x//a/b" AND accessors:"//?/c:/x//a/b/z"'),
        ("//localhost/c$/", "", 'parents:"//localhost/c$/" AND accessors:"//localhost/c$//z"'),
        ("//localhost/c$/", "a/b", 'parents:"//localhost/c$//a/b" AND accessors:"//localhost/c$//a/b/z"'),
        ("//localhost/c$/x", "", 'parents:"//localhost/c$/x/" AND accessors:"//localhost/c$/x//z"'),
        ("//localhost/c$/x", "a/b", 'parents:"//localhost/c$/x//a/b" AND accessors:"//localhost/c$/x//a/b/z"'),
        ("//?/UNC/localhost/c$/", "", 'parents:"//?/UNC/localhost/c$/" AND accessors:"//?/UNC/localhost/c$//z"'),
        (
            "//?/UNC/localhost/c$/",
            "a/b",
            'parents:"//?/UNC/localhost/c$//a/b" AND accessors:"//?/UNC/localhost/c$//a/b/z"',
        ),
        ("//?/UNC/localhost/c$/x", "", 'parents:"//?/UNC/localhost/c$/x/" AND accessors:"//?/UNC/localhost/c$/x//z"'),
        (
            "//?/UNC/localhost/c$/x",
            "a/b",
            'parents:"//?/UNC/localhost/c$/x//a/b" AND accessors:"//?/UNC/localhost/c$/x//a/b/z"',
        ),
    ]:
        assert create_docs_query_exact(create_accessor_path(root, rel), name) == query
    # check escaping
    assert (
        create_docs_query_exact('//a/b"\\"\\x', 'e"\\"\\f')
        == 'parents:"//a/b\\"\\\\\\"\\\\x" AND accessors:"//a/b\\"\\\\\\"\\\\x/e\\"\\\\\\"\\\\f"'
    )
    # NOTE: accessor path to fs path conversion is only correct for the current platform and not universally
    w = "/" if sys.platform.startswith("win") else ""
    # check exact query for root-document
    for root, query in [
        ("/", 'path:"/"'),
        ("/x", 'path:"/x"'),
        ("//?/c:/", f'path:"//?/c:{w}"'),
        ("//?/c:/x", 'path:"//?/c:/x"'),
        ("//localhost/c$/", f'path:"//localhost/c${w}"'),
        ("//localhost/c$/x", 'path:"//localhost/c$/x"'),
        ("//?/UNC/localhost/c$/", f'path:"//?/UNC/localhost/c${w}"'),
        ("//?/UNC/localhost/c$/x", 'path:"//?/UNC/localhost/c$/x"'),
    ]:
        assert create_docs_query_exact(create_accessor_path(root), "") == query


def test_indexer_utility_create_docs_query_tree():
    for root, rel, query in [
        ("/", "", 'accessors:"/"'),
        ("/", "a/b", 'accessors:"//a/b"'),
        ("/x", "", 'accessors:"/x/"'),
        ("/x", "a/b", 'accessors:"/x//a/b"'),
        ("//?/c:/", "", 'accessors:"//?/c:/"'),
        ("//?/c:/", "a/b", 'accessors:"//?/c://a/b"'),
        ("//?/c:/x", "", 'accessors:"//?/c:/x/"'),
        ("//?/c:/x", "a/b", 'accessors:"//?/c:/x//a/b"'),
        ("//localhost/c$/", "", 'accessors:"//localhost/c$/"'),
        ("//localhost/c$/", "a/b", 'accessors:"//localhost/c$//a/b"'),
        ("//localhost/c$/x", "", 'accessors:"//localhost/c$/x/"'),
        ("//localhost/c$/x", "a/b", 'accessors:"//localhost/c$/x//a/b"'),
        ("//?/UNC/localhost/c$/", "", 'accessors:"//?/UNC/localhost/c$/"'),
        ("//?/UNC/localhost/c$/", "a/b", 'accessors:"//?/UNC/localhost/c$//a/b"'),
        ("//?/UNC/localhost/c$/x", "", 'accessors:"//?/UNC/localhost/c$/x/"'),
        ("//?/UNC/localhost/c$/x", "a/b", 'accessors:"//?/UNC/localhost/c$/x//a/b"'),
    ]:
        assert create_docs_query_tree(create_accessor_path(root, rel)) == query
    # check escaping
    assert create_docs_query_tree('//a/b"\\"\\x') == 'accessors:"//a/b\\"\\\\\\"\\\\x"'


def test_indexer_utility_create_doc_query_path():
    for path, query in [
        ("/", 'path:"/"'),
        ("/a/b", 'path:"/a/b"'),
        ("/x", 'path:"/x"'),
        ("/x/a/b", 'path:"/x/a/b"'),
        ("//?/c:/", 'path:"//?/c:/"'),
        ("//?/c:/a/b", 'path:"//?/c:/a/b"'),
        ("//?/c:/x", 'path:"//?/c:/x"'),
        ("//?/c:/x/a/b", 'path:"//?/c:/x/a/b"'),
        ("//localhost/c$/", 'path:"//localhost/c$/"'),
        ("//localhost/c$/a/b", 'path:"//localhost/c$/a/b"'),
        ("//localhost/c$/x", 'path:"//localhost/c$/x"'),
        ("//localhost/c$/x/a/b", 'path:"//localhost/c$/x/a/b"'),
        ("//?/UNC/localhost/c$/", 'path:"//?/UNC/localhost/c$/"'),
        ("//?/UNC/localhost/c$/a/b", 'path:"//?/UNC/localhost/c$/a/b"'),
        ("//?/UNC/localhost/c$/x", 'path:"//?/UNC/localhost/c$/x"'),
        ("//?/UNC/localhost/c$/x/a/b", 'path:"//?/UNC/localhost/c$/x/a/b"'),
    ]:
        assert create_doc_query_path(path) == query
    # check escaping
    assert create_doc_query_path('/a/b"\\"\\x') == 'path:"/a/b\\"\\\\\\"\\\\x"'


def test_indexer_utility_convert_accessor_to_path():
    # NOTE: accessor path to fs path conversion is only correct for paths of the current platform and not universally
    w = "/" if sys.platform.startswith("win") else ""
    for root, rel, res in [
        ("/", "", "/"),
        ("/", "a", "/a"),
        ("/", "a/b", "/a/b"),
        ("/x", "", "/x"),
        ("/x", "a", "/x/a"),
        ("/x", "a/b", "/x/a/b"),
        ("//?/c:/", "", f"//?/c:{w}"),
        ("//?/c:/", "a", "//?/c:/a"),
        ("//?/c:/", "a/b", "//?/c:/a/b"),
        ("//?/c:/x", "", "//?/c:/x"),
        ("//?/c:/x", "a", "//?/c:/x/a"),
        ("//?/c:/x", "a/b", "//?/c:/x/a/b"),
        ("//localhost/c$/", "", f"//localhost/c${w}"),
        ("//localhost/c$/", "a", "//localhost/c$/a"),
        ("//localhost/c$/", "a/b", "//localhost/c$/a/b"),
        ("//localhost/c$/x", "", "//localhost/c$/x"),
        ("//localhost/c$/x", "a", "//localhost/c$/x/a"),
        ("//localhost/c$/x", "a/b", "//localhost/c$/x/a/b"),
        ("//?/UNC/localhost/c$/", "", f"//?/UNC/localhost/c${w}"),
        ("//?/UNC/localhost/c$/", "a", "//?/UNC/localhost/c$/a"),
        ("//?/UNC/localhost/c$/", "a/b", "//?/UNC/localhost/c$/a/b"),
        ("//?/UNC/localhost/c$/x", "", "//?/UNC/localhost/c$/x"),
        ("//?/UNC/localhost/c$/x", "a", "//?/UNC/localhost/c$/x/a"),
        ("//?/UNC/localhost/c$/x", "a/b", "//?/UNC/localhost/c$/x/a/b"),
    ]:
        assert convert_accessor_to_path(create_accessor_path(root, rel)) == Path(root, rel).as_posix() == res


def test_convert_accessor_to_parent_accessor():
    for accessor_path, parent_accessor_path, name in [
        ("/", "/", ""),
        ("//a", "/", "a"),
        ("//a/b", "//a", "b"),
        ("/x/", "/x/", ""),
        ("/x//a", "/x/", "a"),
        ("/x//a/b", "/x//a", "b"),
        ("//?/c:/", "//?/c:/", ""),
        ("//?/c://a", "//?/c:/", "a"),
        ("//?/c://a/b", "//?/c://a", "b"),
        ("//?/c:/x/", "//?/c:/x/", ""),
        ("//?/c:/x//a", "//?/c:/x/", "a"),
        ("//?/c:/x//a/b", "//?/c:/x//a", "b"),
        ("//localhost/c$/", "//localhost/c$/", ""),
        ("//localhost/c$//a", "//localhost/c$/", "a"),
        ("//localhost/c$//a/b", "//localhost/c$//a", "b"),
        ("//localhost/c$/x/", "//localhost/c$/x/", ""),
        ("//localhost/c$/x//a", "//localhost/c$/x/", "a"),
        ("//localhost/c$/x//a/b", "//localhost/c$/x//a", "b"),
        ("//?/UNC/localhost/c$/", "//?/UNC/localhost/c$/", ""),
        ("//?/UNC/localhost/c$//a", "//?/UNC/localhost/c$/", "a"),
        ("//?/UNC/localhost/c$//a/b", "//?/UNC/localhost/c$//a", "b"),
        ("//?/UNC/localhost/c$/x/", "//?/UNC/localhost/c$/x/", ""),
        ("//?/UNC/localhost/c$/x//a", "//?/UNC/localhost/c$/x/", "a"),
        ("//?/UNC/localhost/c$/x//a/b", "//?/UNC/localhost/c$/x//a", "b"),
    ]:
        assert convert_accessor_to_parent_accessor(accessor_path) == (parent_accessor_path, name)
