from __future__ import annotations

from app.jobs.rebuild_shell_parents_from_variation_rules import run_rebuild_shell_parents
from app.jobs.remove_shell_parents import _build_variation_rule_export
from db.manual_variation_assignments import list_manual_variation_assignments, replace_manual_variation_assignments
from db.models import (
    MasterCollectionRegistry,
    MasterProduct,
    MasterProductAttributeValue,
    MasterProductImage,
    MasterProductLocationAvailability,
    MasterProductPrice,
    MasterProductRelation,
    ProductChannelAssignment,
)


def _product(sku: str, name: str, collection: str = "Anna Caramel Harvest") -> MasterProduct:
    return MasterProduct(
        sku=sku,
        name=name,
        collection=collection,
        status="active",
        row_hash=sku.lower(),
        is_active=True,
    )


def _collection(code: str, name: str, path_slug: str) -> MasterCollectionRegistry:
    return MasterCollectionRegistry(
        code=code,
        name=name,
        path_slug=path_slug,
        is_active=True,
        aliases={"source_collection_code": code, "alias_codes": [code]},
    )


def test_build_variation_rule_export_round_trips_manual_templates(catalog_intent_session):
    session = catalog_intent_session
    session.add_all(
        [
            _collection("ACH", "Anna Caramel Harvest", "kitchen-cabinets/anna-caramel-harvest"),
            _product("ACH-B12", "ACH Base 12"),
            _product("ACH-B15", "ACH Base 15"),
        ]
    )
    session.commit()

    replace_manual_variation_assignments(
        session,
        {
            "templates": [
                {
                    "source_parent_sku": "B-PARENT",
                    "source_parent_name": "Base Cabinet Parent",
                    "option_attrs": ["variation_width_in"],
                    "collections": [{"collection_code": "ACH"}],
                    "children": [
                        {"source_sku": "B12", "option_mapping": {"variation_width_in": "12"}},
                        {"source_sku": "B15", "option_mapping": {"variation_width_in": "15"}},
                    ],
                }
            ],
            "assign_channels": [],
            "create_identity_mappings": False,
        },
    )
    session.commit()

    parent_rows = session.query(MasterProduct).filter(MasterProduct.sku == "ACH-B-PARENT").all()
    exported = _build_variation_rule_export(session, parent_rows)

    assert exported["template_count"] == 1
    assert exported["source_parent_skus"] == ["B-PARENT"]
    assert exported["templates"][0]["source_parent_sku"] == "B-PARENT"
    assert [child["source_sku"] for child in exported["templates"][0]["children"]] == ["B12", "B15"]


def test_run_rebuild_shell_parents_recreates_parents_from_export_payload(catalog_intent_session):
    session = catalog_intent_session
    session.add_all(
        [
            _collection("ACH", "Anna Caramel Harvest", "kitchen-cabinets/anna-caramel-harvest"),
            _collection("ASG", "Anna Stone Gray", "kitchen-cabinets/anna-stone-gray"),
            _product("ACH-B12", "ACH Base 12", "Anna Caramel Harvest"),
            _product("ACH-B15", "ACH Base 15", "Anna Caramel Harvest"),
            _product("ASG-B12", "ASG Base 12", "Anna Stone Gray"),
            _product("ASG-B15", "ASG Base 15", "Anna Stone Gray"),
        ]
    )
    session.commit()

    exported_templates = [
        {
            "source_parent_sku": "B-PARENT",
            "source_parent_name": "Base Cabinet Parent",
            "option_attrs": ["variation_width_in"],
            "collections": [{"collection_code": "ACH"}, {"collection_code": "ASG"}],
            "children": [
                {"source_sku": "B12", "option_mapping": {"variation_width_in": "12"}},
                {"source_sku": "B15", "option_mapping": {"variation_width_in": "15"}},
            ],
        }
    ]

    dry_run = run_rebuild_shell_parents(
        session,
        templates=exported_templates,
        assign_channels=[],
        create_identity_mappings=False,
        apply=False,
    )
    assert dry_run["dry_run"] is True
    assert dry_run["parent_skus"] == ["ACH-B-PARENT", "ASG-B-PARENT"]
    assert session.query(MasterProduct).filter(MasterProduct.sku.in_(["ACH-B-PARENT", "ASG-B-PARENT"])).count() == 0

    result = run_rebuild_shell_parents(
        session,
        templates=exported_templates,
        assign_channels=[],
        create_identity_mappings=False,
        apply=True,
    )

    assert result["parents_upserted"] == 2
    assert result["relations_upserted"] == 4

    parents = (
        session.query(MasterProduct)
        .filter(MasterProduct.sku.in_(["ACH-B-PARENT", "ASG-B-PARENT"]))
        .order_by(MasterProduct.sku)
        .all()
    )
    assert [parent.sku for parent in parents] == ["ACH-B-PARENT", "ASG-B-PARENT"]
    assert all(parent.raw_payload["generated_by"] == "manual_variation" for parent in parents)

    relations = (
        session.query(MasterProductRelation)
        .filter(MasterProductRelation.parent_sku.in_(["ACH-B-PARENT", "ASG-B-PARENT"]))
        .order_by(MasterProductRelation.parent_sku, MasterProductRelation.sort_order)
        .all()
    )
    assert len(relations) == 4


def test_saved_manual_variation_rules_survive_parent_shell_deletion(catalog_intent_session):
    session = catalog_intent_session
    session.add_all(
        [
            _collection("ACH", "Anna Caramel Harvest", "kitchen-cabinets/anna-caramel-harvest"),
            _product("ACH-B12", "ACH Base 12"),
            _product("ACH-B15", "ACH Base 15"),
        ]
    )
    session.commit()

    replace_manual_variation_assignments(
        session,
        {
            "templates": [
                {
                    "source_parent_sku": "B-PARENT",
                    "source_parent_name": "Base Cabinet Parent",
                    "option_attrs": ["variation_width_in"],
                    "collections": [{"collection_code": "ACH"}],
                    "children": [
                        {"source_sku": "B12", "option_mapping": {"variation_width_in": "12"}},
                        {"source_sku": "B15", "option_mapping": {"variation_width_in": "15"}},
                    ],
                }
            ],
            "assign_channels": [],
            "create_identity_mappings": False,
        },
    )
    session.commit()

    parent = session.query(MasterProduct).filter(MasterProduct.sku == "ACH-B-PARENT").one()
    session.query(MasterProductRelation).filter(MasterProductRelation.parent_sku == "ACH-B-PARENT").delete()
    session.query(MasterProductAttributeValue).filter(MasterProductAttributeValue.product_id == parent.id).delete()
    session.query(MasterProductPrice).filter(MasterProductPrice.product_id == parent.id).delete()
    session.query(MasterProductLocationAvailability).filter(MasterProductLocationAvailability.product_id == parent.id).delete()
    session.query(MasterProductImage).filter(MasterProductImage.product_id == parent.id).delete()
    session.query(ProductChannelAssignment).filter(ProductChannelAssignment.product_id == parent.id).delete()
    session.query(MasterProduct).filter(MasterProduct.sku == "ACH-B-PARENT").delete()
    session.commit()

    listed = list_manual_variation_assignments(session)
    assert listed["source"] == "manual_variation_assignment_table"
    assert listed["template_count"] == 1
    assert listed["templates"][0]["source_parent_sku"] == "B-PARENT"
    assert [child["source_sku"] for child in listed["templates"][0]["children"]] == ["B12", "B15"]
