import pytest
from sqlalchemy import select

from db.collection_path_guard import (
    filter_suffix_only_category_targets,
    is_polluted_collection_name,
    is_polluted_hub_collection_path,
    is_suffix_only_polluted_collection,
    list_polluted_collection_paths,
)
from db.master_taxonomy_hierarchy import build_hierarchy_from_master_catalog
from db.models import MasterProduct, MasterTaxonomyChannelLink, MasterTaxonomyNode


def test_suffix_only_polluted_collection_detects_color_tail(catalog_intent_session):
    session = catalog_intent_session
    session.add(
        MasterProduct(
            sku="HPW-B15",
            name="Base",
            category_l1="Kitchen Cabinets",
            collection="Anna Stone Gray",
            row_hash="h1",
            is_active=True,
        )
    )
    session.flush()

    assert is_suffix_only_polluted_collection(session, "Stone Gray", category_l1="Kitchen Cabinets") is True
    assert is_suffix_only_polluted_collection(session, "Anna Stone Gray", category_l1="Kitchen Cabinets") is False

    session.add(
        MasterProduct(
            sku="HPW-B12",
            name="Base",
            category_l1="Kitchen Cabinets",
            collection="Harriet Pearl White",
            row_hash="h2",
            is_active=True,
        )
    )
    session.flush()
    assert is_suffix_only_polluted_collection(session, "Pearl White", category_l1="Kitchen Cabinets") is True


def test_suffix_only_polluted_collection_detects_prefix_trimmed_series_name(catalog_intent_session):
    session = catalog_intent_session
    session.add(
        MasterProduct(
            sku="PEM-B12",
            name="Base",
            category_l1="Kitchen Cabinets",
            collection="Plymouth Espresso Maple",
            row_hash="h-pem",
            is_active=True,
        )
    )
    session.flush()

    assert is_suffix_only_polluted_collection(session, "Plymouth Espresso", category_l1="Kitchen Cabinets") is True
    assert is_suffix_only_polluted_collection(session, "Plymouth Espresso Maple", category_l1="Kitchen Cabinets") is False


def test_filter_suffix_only_category_targets_drops_ocean_blue(catalog_intent_session):
    session = catalog_intent_session
    session.add(
        MasterProduct(
            sku="EOB-B15",
            name="Base",
            category_l1="Kitchen Cabinets",
            collection="Eleanor Ocean Blue",
            row_hash="h-eob",
            is_active=True,
        )
    )
    session.flush()

    filtered = filter_suffix_only_category_targets(
        session,
        [
            "All Products",
            "Kitchen Cabinets",
            "Kitchen Cabinets/Ocean Blue",
            "Ocean Blue",
            "Kitchen Cabinets/Eleanor Ocean Blue",
            "Eleanor Ocean Blue",
        ],
        category_l1="Kitchen Cabinets",
    )

    assert filtered == [
        "All Products",
        "Kitchen Cabinets",
        "Kitchen Cabinets/Eleanor Ocean Blue",
    ]


def test_polluted_collection_detects_brand_decorated_duplicate(catalog_intent_session):
    session = catalog_intent_session
    session.add(
        MasterProduct(
            sku="ACH-B15",
            name="Base",
            category_l1="Kitchen Cabinets",
            collection="Anna Caramel Harvest",
            row_hash="h-ach",
            is_active=True,
        )
    )
    session.add(
        MasterProduct(
            sku="QMF-B15",
            name="Base",
            category_l1="Kitchen Cabinets",
            collection="Quest Metro Frost",
            row_hash="h-qmf",
            is_active=True,
        )
    )
    session.flush()

    assert is_polluted_collection_name(session, "Anna Caramel Harvest Port & Bell", category_l1="Kitchen Cabinets")
    assert is_polluted_collection_name(session, "Quest Metro Frost Fabuwood", category_l1="Kitchen Cabinets")
    assert not is_polluted_collection_name(session, "Anna Caramel Harvest", category_l1="Kitchen Cabinets")


def test_polluted_collection_detects_accessory_finish_alias(catalog_intent_session):
    session = catalog_intent_session
    session.add(
        MasterProduct(
            sku="ASW-B15",
            name="Base",
            category_l1="Kitchen Cabinets",
            collection="Anna Snow White",
            row_hash="h-asw",
            is_active=True,
        )
    )
    session.add(
        MasterProduct(
            sku="MBR-B15",
            name="Base",
            category_l1="Kitchen Cabinets",
            collection="Maya Black Rift White Oak",
            row_hash="h-mbr",
            is_active=True,
        )
    )
    session.flush()

    assert is_polluted_collection_name(session, "Snow White Accessories", category_l1="Kitchen Cabinets")
    assert is_polluted_collection_name(session, "Black Rift White Oak Accessories", category_l1="Kitchen Cabinets")
    assert not is_polluted_collection_name(session, "Base Cabinets", category_l1="Kitchen Cabinets")


def test_filter_polluted_targets_keeps_real_category_paths(catalog_intent_session):
    session = catalog_intent_session
    session.add(
        MasterProduct(
            sku="ASW-B15",
            name="Base",
            category_l1="Kitchen Cabinets",
            collection="Anna Snow White",
            row_hash="h-asw-filter",
            is_active=True,
        )
    )
    session.flush()

    filtered = filter_suffix_only_category_targets(
        session,
        [
            "All Products",
            "Kitchen Cabinets",
            "Kitchen Cabinets/Base Cabinets",
            "Kitchen Cabinets/Snow White Accessories",
            "Kitchen Cabinets/Anna Snow White",
        ],
        category_l1="Kitchen Cabinets",
    )

    assert filtered == [
        "All Products",
        "Kitchen Cabinets",
        "Kitchen Cabinets/Base Cabinets",
        "Kitchen Cabinets/Anna Snow White",
    ]


def test_polluted_hub_collection_path(catalog_intent_session):
    session = catalog_intent_session
    session.add(
        MasterProduct(
            sku="HPW-B15",
            name="Base",
            category_l1="Kitchen Cabinets",
            collection="Harriet Pearl White",
            row_hash="h3",
            is_active=True,
        )
    )
    session.flush()

    assert is_polluted_hub_collection_path(session, "kitchen-cabinets/pearl-white") is True
    assert is_polluted_hub_collection_path(session, "kitchen-cabinets/harriet-pearl-white") is False


def test_list_polluted_collection_paths(catalog_intent_session):
    session = catalog_intent_session
    session.add(
        MasterProduct(
            sku="QMF-1",
            name="Base",
            category_l1="Kitchen Cabinets",
            collection="Quest Metro Frost",
            row_hash="h4",
            is_active=True,
        )
    )
    session.add(
        MasterTaxonomyNode(
            node_kind="collection",
            code="metro-frost",
            name="Metro Frost",
            path_slug="kitchen-cabinets/metro-frost",
            is_active=True,
        )
    )
    session.flush()

    polluted = list_polluted_collection_paths(session, hub_path_slug="kitchen-cabinets")
    slugs = {row["path_slug"] for row in polluted}
    assert "kitchen-cabinets/metro-frost" in slugs


def test_build_hierarchy_skips_polluted_collection_path(catalog_intent_session):
    session = catalog_intent_session
    session.add(
        MasterProduct(
            sku="ASG-B15",
            name="Base",
            category_l1="Kitchen Cabinets",
            collection="Anna Stone Gray",
            row_hash="h5",
            is_active=True,
        )
    )
    session.flush()

    stats = build_hierarchy_from_master_catalog(session, dry_run=False, allow_invent=True)
    assert stats["polluted_skipped"] >= 0

    bad = session.scalar(
        select(MasterTaxonomyNode).where(MasterTaxonomyNode.path_slug == "kitchen-cabinets/stone-gray").limit(1)
    )
    assert bad is None


def test_list_polluted_remote_targets_from_inactive_taxonomy(catalog_intent_session):
    session = catalog_intent_session
    from db.collection_path_guard import list_polluted_remote_catalog_targets
    from db.models import MasterTaxonomyChannelLink

    session.add(
        MasterProduct(
            sku="ASG-B15",
            name="Base",
            category_l1="Kitchen Cabinets",
            collection="Anna Stone Gray",
            row_hash="h6",
            is_active=True,
        )
    )
    node = MasterTaxonomyNode(
        node_kind="collection",
        code="stone-gray",
        name="Stone Gray",
        path_slug="kitchen-cabinets/stone-gray",
        is_active=False,
    )
    session.add(node)
    session.flush()
    session.add(
        MasterTaxonomyChannelLink(
            taxonomy_node_id=node.id,
            channel_code="magento",
            connection_id=1,
            taxonomy_kind="collection",
            remote_id="501",
            is_active=False,
        )
    )
    session.add(
        MasterTaxonomyChannelLink(
            taxonomy_node_id=node.id,
            channel_code="shopify",
            connection_id=1,
            taxonomy_kind="collection",
            remote_id="gid://shopify/Collection/901",
            is_active=False,
        )
    )
    session.flush()

    targets = list_polluted_remote_catalog_targets(
        session,
        hub_path_slug="kitchen-cabinets",
        magento_connection_id=1,
        shopify_connection_id=1,
        include_inactive_nodes=True,
    )
    remote_ids = {(row["channel_code"], row["remote_id"]) for row in targets}
    assert ("magento", "501") in remote_ids
    assert ("shopify", "gid://shopify/Collection/901") in remote_ids


def test_list_polluted_magento_categories_from_registry(catalog_intent_session):
    session = catalog_intent_session
    from datetime import datetime, timezone

    from db.collection_path_guard import list_polluted_magento_categories_from_registry
    from db.models import MagentoCategoryRegistry, MagentoConnection, MasterTaxonomyChannelLink, MasterTaxonomyNode

    session.add(
        MagentoConnection(
            id=1,
            store_base_url="https://magento.test",
            environment="test",
            consumer_key="ck",
            consumer_secret="cs",
            access_token="at",
            access_token_secret="ts",
        )
    )
    session.flush()
    fetched_at = datetime.now(timezone.utc)
    for category_id, path_names, name, level in (
        (160, "Default Category/Kitchen Cabinets/Port & Bell/Anna Stone Gray", "Anna Stone Gray", 4),
        (186, "Default Category/Kitchen Cabinets/Port & Bell/Stone Gray", "Stone Gray", 4),
        (356, "Default Category/Kitchen Cabinets/Stone Gray", "Stone Gray", 3),
        (267, "Default Category/Stone Gray", "Stone Gray", 2),
        (266, "Default Category/Anna Stone Gray", "Anna Stone Gray", 2),
        (174, "Default Category/Kitchen Cabinets/Fabuwood/Metro Frost", "Metro Frost", 4),
        (212, "Default Category/Kitchen Cabinets/Quest Metro Frost", "Quest Metro Frost", 3),
        (36, "Default Category/Kitchen Cabinets/Base Cabinets", "Base Cabinets", 3),
        (299, "Default Category/Kitchen Cabinets/Anna Stone Gray", "Anna Stone Gray", 3),
    ):
        session.add(
            MagentoCategoryRegistry(
                connection_id=1,
                category_id=category_id,
                parent_id=2,
                name=name,
                path=f"/1/2/{category_id}",
                path_names=path_names,
                level=level,
                is_active=True,
                fetched_at=fetched_at,
            )
        )
    node = MasterTaxonomyNode(
        node_kind="collection",
        code="anna-stone-gray",
        name="Kitchen Cabinets / Anna Stone Gray",
        path_slug="kitchen-cabinets/anna-stone-gray",
        is_active=True,
    )
    session.add(node)
    session.flush()
    session.add(
        MasterTaxonomyChannelLink(
            taxonomy_node_id=node.id,
            channel_code="magento",
            connection_id=1,
            taxonomy_kind="collection",
            remote_id="299",
            is_active=True,
        )
    )
    session.flush()

    targets = list_polluted_magento_categories_from_registry(session, connection_id=1)
    by_id = {row["remote_id"]: row for row in targets}

    assert "299" not in by_id
    assert "36" not in by_id
    assert "186" in by_id
    assert "356" in by_id
    assert "267" in by_id
    assert "266" in by_id
    assert by_id["186"]["purge_reason"] == "not_in_taxonomy"
    assert "160" in by_id
    assert "174" in by_id
    assert "212" in by_id


def test_root_orphan_skipped_when_taxonomy_owns_canonical_copy(catalog_intent_session):
    session = catalog_intent_session
    from datetime import datetime, timezone

    from db.collection_path_guard import list_polluted_magento_categories_from_registry
    from db.models import MagentoCategoryRegistry, MagentoConnection, MasterTaxonomyChannelLink, MasterTaxonomyNode

    session.add(
        MagentoConnection(
            id=2,
            store_base_url="https://magento.test",
            environment="test",
            consumer_key="ck",
            consumer_secret="cs",
            access_token="at",
            access_token_secret="ts",
        )
    )
    session.flush()
    fetched_at = datetime.now(timezone.utc)
    for category_id, path_names, name, level in (
        (216, "Default Category/Anna Caramel Harvest", "Anna Caramel Harvest", 2),
        (296, "Default Category/Kitchen Cabinets/Anna Caramel Harvest", "Anna Caramel Harvest", 3),
    ):
        session.add(
            MagentoCategoryRegistry(
                connection_id=2,
                category_id=category_id,
                parent_id=2,
                name=name,
                path=f"/1/2/{category_id}",
                path_names=path_names,
                level=level,
                is_active=True,
                fetched_at=fetched_at,
            )
        )
    node = MasterTaxonomyNode(
        node_kind="collection",
        code="anna-caramel-harvest",
        name="Kitchen Cabinets / Anna Caramel Harvest",
        path_slug="kitchen-cabinets/anna-caramel-harvest",
        is_active=True,
    )
    session.add(node)
    session.flush()
    session.add(
        MasterTaxonomyChannelLink(
            taxonomy_node_id=node.id,
            channel_code="magento",
            connection_id=2,
            taxonomy_kind="collection",
            remote_id="296",
            is_active=True,
        )
    )
    session.flush()

    targets = list_polluted_magento_categories_from_registry(session, connection_id=2)
    by_id = {row["remote_id"]: row for row in targets}

    assert "296" not in by_id
    assert "216" in by_id
    assert by_id["216"]["purge_reason"] == "not_in_taxonomy"


def test_build_hierarchy_does_not_reactivate_deactivated_node(catalog_intent_session):
    session = catalog_intent_session
    session.add(
        MasterProduct(
            sku="ASG-B15",
            name="Base",
            category_l1="Kitchen Cabinets",
            collection="Anna Stone Gray",
            row_hash="h5b",
            is_active=True,
        )
    )
    session.add(
        MasterTaxonomyNode(
            node_kind="collection",
            code="stone-gray",
            name="Stone Gray",
            path_slug="kitchen-cabinets/stone-gray",
            is_active=False,
        )
    )
    session.flush()

    build_hierarchy_from_master_catalog(session, dry_run=False, allow_invent=True)

    node = session.scalar(
        select(MasterTaxonomyNode).where(MasterTaxonomyNode.path_slug == "kitchen-cabinets/stone-gray")
    )
    assert node is not None
    assert node.is_active is False


def test_shopify_polluted_skips_structural_and_flags_duplicate_title(catalog_intent_session):
    session = catalog_intent_session
    from datetime import datetime, timezone

    from db.collection_path_guard import list_polluted_shopify_collections_from_registry
    from db.models import MasterTaxonomyChannelLink, MasterTaxonomyNode, ShopifyCollectionRegistry, ShopifyConnection

    session.add(
        ShopifyConnection(
            id=1,
            shop_code="test",
            shop_domain="test.myshopify.com",
            admin_access_token="token",
            status="active",
        )
    )
    session.flush()
    fetched_at = datetime.now(timezone.utc)
    for collection_id, title, handle in (
        ("gid://shopify/Collection/467047448803", "Wall Cabinets", "wall-cabinets"),
        ("gid://shopify/Collection/472279744739", "Wall Cabinets", "wall-cabinets-dup"),
        ("gid://shopify/Collection/111", "Anna Caramel Harvest", "anna-caramel-harvest"),
        ("gid://shopify/Collection/222", "Anna Caramel Harvest", "anna-caramel-harvest-dup"),
        ("gid://shopify/Collection/333", "Frost", "frost-orphan"),
    ):
        session.add(
            ShopifyCollectionRegistry(
                connection_id=1,
                shop_code="test",
                collection_id=collection_id,
                handle=handle,
                title=title,
                collection_type="manual",
                product_count=0,
                fetched_at=fetched_at,
            )
        )
    wall = MasterTaxonomyNode(
        node_kind="category",
        code="wall-cabinets",
        name="Wall Cabinets",
        path_slug="kitchen-cabinets/wall-cabinets",
        is_active=True,
    )
    collection = MasterTaxonomyNode(
        node_kind="collection",
        code="anna-caramel-harvest",
        name="Kitchen Cabinets / Anna Caramel Harvest",
        path_slug="kitchen-cabinets/anna-caramel-harvest",
        is_active=True,
    )
    session.add_all([wall, collection])
    session.flush()
    session.add(
        MasterTaxonomyChannelLink(
            taxonomy_node_id=wall.id,
            channel_code="shopify",
            connection_id=1,
            taxonomy_kind="collection",
            remote_id="gid://shopify/Collection/467047448803",
            is_active=True,
        )
    )
    session.add(
        MasterTaxonomyChannelLink(
            taxonomy_node_id=collection.id,
            channel_code="shopify",
            connection_id=1,
            taxonomy_kind="collection",
            remote_id="gid://shopify/Collection/111",
            is_active=True,
        )
    )
    session.flush()

    targets = list_polluted_shopify_collections_from_registry(session, connection_id=1)
    by_id = {row["remote_id"]: row for row in targets}

    # Structural category label — never a polluted collection landing.
    assert "gid://shopify/Collection/467047448803" not in by_id
    assert "gid://shopify/Collection/472279744739" not in by_id
    # Managed collection landing stays protected.
    assert "gid://shopify/Collection/111" not in by_id
    # Unmanaged duplicate of a managed collection title is reported with pointer.
    assert "gid://shopify/Collection/222" in by_id
    assert by_id["gid://shopify/Collection/222"]["managed_same_title_remote_ids"] == [
        "gid://shopify/Collection/111"
    ]
    assert by_id["gid://shopify/Collection/222"]["path_slug_source"] == "registry_title"
    # Unmanaged unknown collection landing still reported.
    assert "gid://shopify/Collection/333" in by_id
    assert by_id["gid://shopify/Collection/333"]["note"] == "unmanaged_collection_landing"
