from __future__ import annotations

import pytest

from simorgh.apps.organizations.services import (
    HierarchyError,
    ancestors_of,
    descendant_ids,
    descendants_of,
    move_node,
    rebuild_paths,
)


@pytest.mark.django_db
def test_create_node_assigns_path_and_depth(acme_tree):
    root, eu, de = acme_tree["root"], acme_tree["eu"], acme_tree["de"]
    assert root.path_string == f"/{root.pk}/"
    assert eu.path_string == f"/{root.pk}/{eu.pk}/"
    assert de.depth == 2


@pytest.mark.django_db
def test_descendants_and_ancestors(acme_tree):
    root, eu, de, us = (acme_tree[k] for k in ("root", "eu", "de", "us"))

    descendants = set(descendants_of(root).values_list("pk", flat=True))
    assert descendants == {eu.pk, de.pk, us.pk}

    ancestors = list(ancestors_of(de).values_list("pk", flat=True))
    assert ancestors == [root.pk, eu.pk]

    assert descendant_ids([eu]) == {eu.pk, de.pk}


@pytest.mark.django_db
def test_move_node_rewrites_subtree(acme_tree):
    eu, de, us = (acme_tree[k] for k in ("eu", "de", "us"))
    move_node(eu, new_parent=us)
    eu.refresh_from_db()
    de.refresh_from_db()
    assert eu.path_string.startswith(us.path_string)
    assert de.path_string.startswith(eu.path_string)
    assert de.depth == eu.depth + 1


@pytest.mark.django_db
def test_move_into_descendant_is_rejected(acme_tree):
    eu, de = acme_tree["eu"], acme_tree["de"]
    with pytest.raises(HierarchyError):
        move_node(eu, new_parent=de)


@pytest.mark.django_db
def test_rebuild_paths_is_idempotent(tenant_acme, acme_tree):
    assert rebuild_paths(tenant_acme.pk) == 0
