from datetime import datetime, timezone

from db.channel_listing_path import (
    bulk_assign_listing_paths,
    upsert_listing_path,
    upsert_listing_path_target,
)
from db.master_taxonomy_hierarchy import magento_registry_candidates_for_node
from db.master_taxonomy_sync import bootstrap_master_taxonomy, reconcile_magento_taxonomy_duplicates
from db.models import (
    MagentoCategoryRegistry,
    MagentoConnection,
    MasterProduct,
    MasterTaxonomyChannelLink,
    MasterTaxonomyNode,
    ProductChannelTaxonomyAssignment,
)
from db.product_channel_taxonomy import (
    resolve_magento_category_targets,
    sku_has_master_taxonomy_placements,
    upsert_sku_taxonomy_assignment,
)


def _seed_magento_connection(session) -> int:
    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",
            status="active",
        )
    )
    session.flush()
    return 1


def test_sku_has_master_taxonomy_placements(catalog_intent_session):
    session = catalog_intent_session
    session.add(
        MasterProduct(
            sku="ASG-B15",
            name="Base",
            category_l1="Kitchen Cabinets",
            collection="Anna Snow White",
            row_hash="h1",
            is_active=True,
        )
    )
    session.flush()
    bootstrap_master_taxonomy(session, dry_run=False)
    collection = next(
        n
        for n in bootstrap_master_taxonomy(session, dry_run=True)["tree"]["collections"]
    )
    upsert_listing_path(
        session,
        path_slug=collection["path_slug"],
        title=collection["name"],
        path_kind="collection",
    )
    bulk_assign_listing_paths(session, path_slugs=[collection["path_slug"]], skus=["ASG-B15"], dry_run=False)
    session.flush()

    assert sku_has_master_taxonomy_placements(session, "ASG-B15") is True
    assert sku_has_master_taxonomy_placements(session, "UNKNOWN") is False


def test_sku_has_master_taxonomy_placements_ignores_descendant_of_inactive_parent(catalog_intent_session):
    session = catalog_intent_session
    hub = MasterTaxonomyNode(
        parent_id=None,
        node_kind="hub",
        code="kitchen-cabinets",
        name="Kitchen Cabinets",
        path_slug="kitchen-cabinets",
        is_active=True,
    )
    session.add(hub)
    session.flush()
    tall = MasterTaxonomyNode(
        parent_id=hub.id,
        node_kind="category",
        code="tall",
        name="Tall",
        path_slug="kitchen-cabinets/tall",
        is_active=False,
    )
    session.add(tall)
    session.flush()
    pantry = MasterTaxonomyNode(
        parent_id=tall.id,
        node_kind="category",
        code="pantry-cabinet",
        name="Pantry Cabinet",
        path_slug="kitchen-cabinets/tall/pantry-cabinet",
        is_active=True,
    )
    session.add(pantry)
    session.flush()

    upsert_listing_path(
        session,
        path_slug=pantry.path_slug,
        title=pantry.name,
        path_kind="category",
    )
    bulk_assign_listing_paths(session, path_slugs=[pantry.path_slug], skus=["ACH-PC1884"], dry_run=False)
    session.flush()

    assert sku_has_master_taxonomy_placements(session, "ACH-PC1884") is False


def test_resolve_magento_exclusive_ignores_legacy_assignments(catalog_intent_session):
    session = catalog_intent_session
    conn_id = _seed_magento_connection(session)
    session.add(
        MasterProduct(
            sku="ASG-B15",
            name="Base",
            category_l1="Kitchen Cabinets",
            collection="Anna Caramel Harvest",
            row_hash="h1",
            is_active=True,
        )
    )
    session.flush()
    bootstrap_master_taxonomy(session, dry_run=False)
    collection = next(
        n
        for n in bootstrap_master_taxonomy(session, dry_run=True)["tree"]["collections"]
        if "caramel" in n["path_slug"]
    )
    node = session.get(MasterTaxonomyNode, collection["id"])
    upsert_listing_path(
        session,
        path_slug=node.path_slug,
        title=node.name,
        path_kind="collection",
    )
    upsert_listing_path_target(
        session,
        path_slug=node.path_slug,
        channel_code="magento",
        remote_id="501",
        taxonomy_kind="collection",
        connection_id=conn_id,
        remote_path="Kitchen Cabinets/Anna Caramel Harvest",
    )
    bulk_assign_listing_paths(session, path_slugs=[node.path_slug], skus=["ASG-B15"], dry_run=False)

    for remote_id in ("111", "222", "333"):
        upsert_sku_taxonomy_assignment(
            session,
            master_sku="ASG-B15",
            channel_code="magento",
            remote_id=remote_id,
            taxonomy_kind="category",
            connection_id=conn_id,
            remote_path=f"Legacy Path {remote_id}",
            match_source="legacy_push",
        )
    session.flush()

    category_ids, category_paths = resolve_magento_category_targets(
        session,
        master_sku="ASG-B15",
        canonical_fields={"category_l1": "Kitchen Cabinets", "collection": "Anna Caramel Harvest"},
        connection_id=conn_id,
    )
    assert category_ids == [501]
    assert "Kitchen Cabinets/Anna Caramel Harvest" in category_paths


def test_resolve_ignores_stale_master_taxonomy_assignments_when_plp_targets_exist(catalog_intent_session):
    """ACH-B12 style: PLP target 307 must win over stale assignment 142 (Wall/Single Door)."""
    session = catalog_intent_session
    conn_id = _seed_magento_connection(session)
    session.add(
        MasterProduct(
            sku="ACH-B12",
            name="Base 12",
            category_l1="Kitchen Cabinets",
            collection="Anna Caramel Harvest",
            row_hash="h1",
            is_active=True,
        )
    )
    session.flush()
    for slug, title, remote_id, remote_path in (
        ("kitchen-cabinets/anna-caramel-harvest", "Anna Caramel Harvest", "296", "Kitchen Cabinets/Anna Caramel Harvest"),
        ("kitchen-cabinets/base-cabinets", "Base Cabinets", "36", "Kitchen Cabinets/Base Cabinets"),
        (
            "kitchen-cabinets/base-cabinets/single-door",
            "Single Door",
            "307",
            "Kitchen Cabinets/Base Cabinets/Single Door Base Cabinet",
        ),
    ):
        upsert_listing_path(session, path_slug=slug, title=title, path_kind="category")
        upsert_listing_path_target(
            session,
            path_slug=slug,
            channel_code="magento",
            remote_id=remote_id,
            taxonomy_kind="category",
            connection_id=conn_id,
            remote_path=remote_path,
        )
    bulk_assign_listing_paths(
        session,
        path_slugs=[
            "kitchen-cabinets/anna-caramel-harvest",
            "kitchen-cabinets/base-cabinets",
            "kitchen-cabinets/base-cabinets/single-door",
        ],
        skus=["ACH-B12"],
        dry_run=False,
    )
    upsert_sku_taxonomy_assignment(
        session,
        master_sku="ACH-B12",
        channel_code="magento",
        remote_id="142",
        taxonomy_kind="category",
        connection_id=conn_id,
        remote_path="Kitchen Cabinets/Wall Cabinets/Single Door",
        match_source="master_taxonomy",
    )
    upsert_sku_taxonomy_assignment(
        session,
        master_sku="ACH-B12",
        channel_code="magento",
        remote_id="363",
        taxonomy_kind="category",
        connection_id=conn_id,
        remote_path="Kitchen Cabinets/Frost",
        match_source="manual",
    )
    session.flush()

    category_ids, _ = resolve_magento_category_targets(
        session,
        master_sku="ACH-B12",
        canonical_fields={"category_l1": "Kitchen Cabinets"},
        connection_id=conn_id,
    )
    assert category_ids == [296, 307]
    assert 36 not in category_ids  # L2 shopping facet must not be Magento category membership
    assert 142 not in category_ids
    assert 363 not in category_ids


def test_magento_registry_candidates_rank_canonical_first():
    node = MasterTaxonomyNode(
        id=1,
        node_kind="collection",
        code="anna-caramel-harvest",
        name="Anna Caramel Harvest",
        path_slug="kitchen-cabinets/anna-caramel-harvest",
        sort_order=100,
        is_active=True,
    )
    registry_rows = [
        {
            "category_id": 111,
            "parent_id": 2,
            "name": "Anna Caramel Harvest",
            "path_names": "Default Category/Anna Caramel Harvest",
        },
        {
            "category_id": 222,
            "parent_id": 50,
            "name": "Anna Caramel Harvest",
            "path_names": "Default Category/Kitchen Cabinets/Port & Bell/Anna Caramel Harvest",
        },
        {
            "category_id": 501,
            "parent_id": 40,
            "name": "Anna Caramel Harvest",
            "path_names": "Default Category/Kitchen Cabinets/Anna Caramel Harvest",
        },
    ]
    scored = magento_registry_candidates_for_node(node, registry_rows)
    assert len(scored) == 3
    assert scored[0]["remote_id"] == "501"
    assert scored[0]["is_canonical_path"] is True
    assert scored[0]["duplicate_group_size"] == 3


def test_reconcile_magento_taxonomy_duplicates(catalog_intent_session):
    session = catalog_intent_session
    conn_id = _seed_magento_connection(session)
    session.add(
        MasterProduct(
            sku="ASG-B15",
            name="Base",
            category_l1="Kitchen Cabinets",
            collection="Anna Caramel Harvest",
            row_hash="h1",
            is_active=True,
        )
    )
    session.flush()
    bootstrap_master_taxonomy(session, dry_run=False)
    collection = next(
        n
        for n in bootstrap_master_taxonomy(session, dry_run=True)["tree"]["collections"]
        if "caramel" in n["path_slug"]
    )
    node = session.get(MasterTaxonomyNode, collection["id"])
    now = datetime.now(timezone.utc)
    for row in (
        (111, "Default Category/Anna Caramel Harvest"),
        (501, "Default Category/Kitchen Cabinets/Anna Caramel Harvest"),
    ):
        session.add(
            MagentoCategoryRegistry(
                connection_id=conn_id,
                category_id=row[0],
                parent_id=2,
                name="Anna Caramel Harvest",
                path=f"1/2/{row[0]}",
                path_names=row[1],
                level=3,
                is_active=True,
                fetched_at=now,
            )
        )
    session.add(
        MasterTaxonomyChannelLink(
            taxonomy_node_id=node.id,
            channel_code="magento",
            connection_id=conn_id,
            taxonomy_kind="collection",
            remote_id="111",
            remote_path="Anna Caramel Harvest",
            is_active=True,
        )
    )
    session.flush()

    result = reconcile_magento_taxonomy_duplicates(session, connection_id=conn_id)
    item = next(i for i in result["items"] if i["node_id"] == node.id)
    assert item["has_duplicates"] is True
    assert item["duplicate_count"] == 2
    assert item["linked_remote_id"] == "111"
    assert item["recommended_remote_id"] == "501"
    assert item["needs_review"] is True
    assert item["is_correctly_linked"] is False
    assert result["duplicate_nodes"] >= 1


def test_reconcile_skips_correctly_linked_canonical_node(catalog_intent_session):
    session = catalog_intent_session
    conn_id = _seed_magento_connection(session)
    session.add(
        MasterProduct(
            sku="ASG-B15",
            name="Base",
            category_l1="Kitchen Cabinets",
            collection="Anna Caramel Harvest",
            row_hash="h1",
            is_active=True,
        )
    )
    session.flush()
    bootstrap_master_taxonomy(session, dry_run=False)
    collection = next(
        n
        for n in bootstrap_master_taxonomy(session, dry_run=True)["tree"]["collections"]
        if "caramel" in n["path_slug"]
    )
    node = session.get(MasterTaxonomyNode, collection["id"])
    now = datetime.now(timezone.utc)
    for row in (
        (111, "Default Category/Anna Caramel Harvest"),
        (501, "Default Category/Kitchen Cabinets/Anna Caramel Harvest"),
    ):
        session.add(
            MagentoCategoryRegistry(
                connection_id=conn_id,
                category_id=row[0],
                parent_id=2,
                name="Anna Caramel Harvest",
                path=f"1/2/{row[0]}",
                path_names=row[1],
                level=3,
                is_active=True,
                fetched_at=now,
            )
        )
    session.add(
        MasterTaxonomyChannelLink(
            taxonomy_node_id=node.id,
            channel_code="magento",
            connection_id=conn_id,
            taxonomy_kind="collection",
            remote_id="501",
            remote_path="Anna Caramel Harvest",
            is_active=True,
        )
    )
    session.flush()

    result = reconcile_magento_taxonomy_duplicates(session, connection_id=conn_id)
    assert not any(i["node_id"] == node.id for i in result["items"])
    assert result["resolved_nodes"] >= 1
