from pathlib import Path

from clarabot_nano_common.utility.path.common import normalize_absolute_path

from clarabot_nano.indexer.sync_data import SyncFilesystemParent
from clarabot_nano_tests.testing.file import temp_path


def test_indexer_sync_data_fs_parent_get_cd_as(tmpdir):
    def _new_fs(rel_: str) -> SyncFilesystemParent:
        root_ = Path(normalize_absolute_path(temp_path(tmpdir)))
        root_.mkdir()
        return SyncFilesystemParent(root_.as_posix(), rel_, root_)

    def _new_item(fs_: SyncFilesystemParent, rel_: str, directory: bool = False):
        p_ = fs_.path / rel_
        if directory:
            p_.mkdir()
        else:
            p_.write_bytes(b"test")
        i_ = fs_.add_item(rel_, p_, p_.stat())
        fs_.items.sort(key=lambda x: x.name)
        return i_

    # == root case ==
    fs = _new_fs("")
    assert fs.get_child_dirs_and_already_synchronized(0, [], -1) == ([], [])

    i_a = _new_item(fs, "a")
    qd = ["", "a", "a/b", "b", "--a", "c/b/a", "x"]
    # exists early
    assert fs.get_child_dirs_and_already_synchronized(len(qd), sorted(qd), -1) == ([], ["a"])

    _new_item(fs, "q")
    # exists later
    assert fs.get_child_dirs_and_already_synchronized(len(qd), sorted(qd), -1) == ([], ["a"])

    _new_item(fs, "y")
    i_b = _new_item(fs, "b")
    # exists after full scan
    assert fs.get_child_dirs_and_already_synchronized(len(qd), sorted(qd), -1) == ([], ["a", "b"])
    assert fs.get_child_dirs_and_already_synchronized(len(qd), sorted(qd)) == ([], [])

    _new_item(fs, "d", directory=True)
    assert fs.get_child_dirs_and_already_synchronized(len(qd), sorted(qd), -1) == (["d"], ["a", "b"])
    assert fs.get_child_dirs_and_already_synchronized(len(qd), sorted(qd)) == (["d"], [])

    i_a.path.write_bytes(b"mod")
    assert fs.get_child_dirs_and_already_synchronized(len(qd), sorted(qd), -1) == (["d"], ["b"])
    assert fs.get_child_dirs_and_already_synchronized(len(qd), sorted(qd)) == (["d"], [])

    _new_item(fs, "z", directory=True)
    assert fs.get_child_dirs_and_already_synchronized(len(qd), sorted(qd), -1) == (["d", "z"], ["b"])
    assert fs.get_child_dirs_and_already_synchronized(len(qd), sorted(qd)) == (["d", "z"], [])

    i_b.path.unlink()
    assert fs.get_child_dirs_and_already_synchronized(len(qd), sorted(qd), -1) == (["d", "z"], [])
    assert fs.get_child_dirs_and_already_synchronized(len(qd), sorted(qd)) == (["d", "z"], [])

    # == rel case ==
    fs = _new_fs("gg")
    assert fs.get_child_dirs_and_already_synchronized(0, [], -1) == ([], [])

    # other paths
    (Path(fs.root_path) / "ga").mkdir()
    (Path(fs.root_path) / "g0").mkdir()
    (Path(fs.root_path) / "g1").write_bytes(b"gg1")
    (Path(fs.root_path) / "ggg").mkdir()
    (Path(fs.root_path) / "ggg/gxx").write_bytes(b"gxx")
    (Path(fs.root_path) / "gx").mkdir()
    (Path(fs.root_path) / "g2").write_bytes(b"gg2")

    i_a = _new_item(fs, "a")
    qd = ["gg", "gg/a", "gg/a/b", "gg/b", "gg/--a", "gg/c/b/a", "gg/x", "ggg", "ggg/gxx"]
    # exists early
    assert fs.get_child_dirs_and_already_synchronized(len(qd), sorted(qd), -1) == ([], ["gg/a"])

    _new_item(fs, "q")
    # exists later
    assert fs.get_child_dirs_and_already_synchronized(len(qd), sorted(qd), -1) == ([], ["gg/a"])

    _new_item(fs, "y")
    i_b = _new_item(fs, "b")
    # exists after full scan
    assert fs.get_child_dirs_and_already_synchronized(len(qd), sorted(qd), -1) == ([], ["gg/a", "gg/b"])
    assert fs.get_child_dirs_and_already_synchronized(len(qd), sorted(qd)) == ([], [])

    _new_item(fs, "d", directory=True)
    assert fs.get_child_dirs_and_already_synchronized(len(qd), sorted(qd), -1) == (["gg/d"], ["gg/a", "gg/b"])
    assert fs.get_child_dirs_and_already_synchronized(len(qd), sorted(qd)) == (["gg/d"], [])

    i_a.path.write_bytes(b"mod")
    assert fs.get_child_dirs_and_already_synchronized(len(qd), sorted(qd), -1) == (["gg/d"], ["gg/b"])
    assert fs.get_child_dirs_and_already_synchronized(len(qd), sorted(qd)) == (["gg/d"], [])

    _new_item(fs, "z", directory=True)
    assert fs.get_child_dirs_and_already_synchronized(len(qd), sorted(qd), -1) == (["gg/d", "gg/z"], ["gg/b"])
    assert fs.get_child_dirs_and_already_synchronized(len(qd), sorted(qd)) == (["gg/d", "gg/z"], [])

    i_b.path.unlink()
    assert fs.get_child_dirs_and_already_synchronized(len(qd), sorted(qd), -1) == (["gg/d", "gg/z"], [])
    assert fs.get_child_dirs_and_already_synchronized(len(qd), sorted(qd)) == (["gg/d", "gg/z"], [])

    # exit by finding at prefixing path
    qd.pop()
    qd.pop()
    qd.append("gx")
    assert fs.get_child_dirs_and_already_synchronized(len(qd), sorted(qd), -1) == (["gg/d", "gg/z"], [])
    assert fs.get_child_dirs_and_already_synchronized(len(qd), sorted(qd)) == (["gg/d", "gg/z"], [])
