from sqlalchemy import select

from app.jobs.cleanup_manual_taxonomy_assignments import cleanup_manual_taxonomy_assignments
from db.master_taxonomy_merge import register_taxonomy_path_alias
from db.models import ManualTaxonomyAssignment, ManualTaxonomyAssignmentCollection, MasterTaxonomyNode


def test_cleanup_manual_taxonomy_assignments_rewrites_alias_slug(catalog_intent_session):
    session = catalog_intent_session
    hub = MasterTaxonomyNode(node_kind="hub", code="kitchen-cabinets", name="Kitchen Cabinets", path_slug="kitchen-cabinets")
    parent = MasterTaxonomyNode(
        node_kind="category",
        code="base-cabinets",
        name="Base Cabinets",
        path_slug="kitchen-cabinets/base-cabinets",
        parent_id=None,
    )
    leaf = MasterTaxonomyNode(
        node_kind="category",
        code="sink-base",
        name="Sink Base",
        path_slug="kitchen-cabinets/base-cabinets/sink-base",
        parent_id=None,
    )
    session.add_all([hub, parent, leaf])
    session.flush()
    parent.parent_id = hub.id
    leaf.parent_id = parent.id
    session.flush()

    register_taxonomy_path_alias(
        session,
        alias_path_slug="kitchen-cabinets/base-cabinets/single-door",
        canonical_node_id=leaf.id,
    )

    assignment = ManualTaxonomyAssignment(
        source_sku="B12",
        canonical_taxonomy_path_slug="kitchen-cabinets/base-cabinets/single-door",
        canonical_taxonomy_path_label="Kitchen Cabinets / Base Cabinets / Single Door",
        shopping_l1="base-cabinets",
        shopping_l2="base-cabinets/single-door",
        l2_category="Base Cabinets",
        l3_category="Single Door",
        assignment_status="active",
        raw_payload={
            "source_sku": "B12",
            "canonical_taxonomy_path_slug": "kitchen-cabinets/base-cabinets/single-door",
            "canonical_taxonomy_path_label": "Kitchen Cabinets / Base Cabinets / Single Door",
            "shopping_l1": "base-cabinets",
            "shopping_l2": "base-cabinets/single-door",
            "l2_category": "Base Cabinets",
            "l3_category": "Single Door",
            "collections": [],
        },
    )
    session.add(assignment)
    session.flush()

    summary = cleanup_manual_taxonomy_assignments(session, dry_run=False)
    session.flush()

    refreshed = session.get(ManualTaxonomyAssignment, assignment.id)
    assert refreshed is not None
    assert refreshed.canonical_taxonomy_path_slug == "kitchen-cabinets/base-cabinets/sink-base"
    assert refreshed.canonical_taxonomy_path_label == "Kitchen Cabinets / Base Cabinets / Sink Base"
    assert refreshed.shopping_l2 == "base-cabinets/sink-base"
    assert refreshed.l3_category == "Sink Base"
    assert refreshed.raw_payload["canonical_taxonomy_path_slug"] == "kitchen-cabinets/base-cabinets/sink-base"
    assert summary["updated_assignments"] == 1
    assert summary["updated_payloads"] == 1


def test_cleanup_manual_taxonomy_assignments_merges_duplicate_rules_after_alias_resolution(catalog_intent_session):
    session = catalog_intent_session
    hub = MasterTaxonomyNode(node_kind="hub", code="kitchen-cabinets", name="Kitchen Cabinets", path_slug="kitchen-cabinets")
    parent = MasterTaxonomyNode(
        node_kind="category",
        code="wall-cabinets",
        name="Wall Cabinets",
        path_slug="kitchen-cabinets/wall-cabinets",
        parent_id=None,
    )
    leaf = MasterTaxonomyNode(
        node_kind="category",
        code="basic-wall",
        name="Basic Wall",
        path_slug="kitchen-cabinets/wall-cabinets/basic-wall",
        parent_id=None,
    )
    session.add_all([hub, parent, leaf])
    session.flush()
    parent.parent_id = hub.id
    leaf.parent_id = parent.id
    session.flush()

    register_taxonomy_path_alias(
        session,
        alias_path_slug="kitchen-cabinets/wall-cabinets/legacy-basic-wall",
        canonical_node_id=leaf.id,
    )

    keep = ManualTaxonomyAssignment(
        source_sku="W0930",
        canonical_taxonomy_path_slug="kitchen-cabinets/wall-cabinets/basic-wall",
        assignment_status="active",
        raw_payload={"source_sku": "W0930", "canonical_taxonomy_path_slug": "kitchen-cabinets/wall-cabinets/basic-wall", "collections": []},
    )
    drop = ManualTaxonomyAssignment(
        source_sku="W0930",
        canonical_taxonomy_path_slug="kitchen-cabinets/wall-cabinets/legacy-basic-wall",
        assignment_status="active",
        raw_payload={"source_sku": "W0930", "canonical_taxonomy_path_slug": "kitchen-cabinets/wall-cabinets/legacy-basic-wall", "collections": []},
    )
    session.add_all([keep, drop])
    session.flush()

    keep_child = ManualTaxonomyAssignmentCollection(
        assignment_id=keep.id,
        collection_code="ASG",
        sku_prefix="ASG",
        master_sku="ASG-W0930",
        is_active=True,
    )
    dup_child = ManualTaxonomyAssignmentCollection(
        assignment_id=drop.id,
        collection_code="ASG",
        sku_prefix="ASG",
        master_sku="ASG-W0930",
        is_active=True,
    )
    session.add_all([keep_child, dup_child])
    session.flush()

    summary = cleanup_manual_taxonomy_assignments(session, dry_run=False)
    session.flush()

    assignments = list(
        session.scalars(
            select(ManualTaxonomyAssignment).where(ManualTaxonomyAssignment.source_sku == "W0930").order_by(ManualTaxonomyAssignment.id)
        ).all()
    )
    children = list(
        session.scalars(
            select(ManualTaxonomyAssignmentCollection).order_by(ManualTaxonomyAssignmentCollection.id)
        ).all()
    )

    assert len(assignments) == 1
    assert assignments[0].id == keep.id
    assert assignments[0].canonical_taxonomy_path_slug == "kitchen-cabinets/wall-cabinets/basic-wall"
    assert len(children) == 1
    assert children[0].assignment_id == keep.id
    assert summary["merged_duplicate_rules"] == 1
    assert summary["deleted_duplicate_children"] == 1


def test_cleanup_manual_taxonomy_assignments_reports_unresolved_slug_without_changing_row(catalog_intent_session):
    session = catalog_intent_session
    assignment = ManualTaxonomyAssignment(
        source_sku="X001",
        canonical_taxonomy_path_slug="kitchen-cabinets/does-not-exist",
        assignment_status="active",
        raw_payload={"source_sku": "X001", "canonical_taxonomy_path_slug": "kitchen-cabinets/does-not-exist", "collections": []},
    )
    session.add(assignment)
    session.flush()

    summary = cleanup_manual_taxonomy_assignments(session, dry_run=False)
    session.flush()

    refreshed = session.get(ManualTaxonomyAssignment, assignment.id)
    assert refreshed is not None
    assert refreshed.canonical_taxonomy_path_slug == "kitchen-cabinets/does-not-exist"
    assert summary["unresolved_count"] == 1
    assert summary["updated_assignments"] == 0
