from db.channel_capabilities import resolve_product_structure
from db.channel_exports import build_channel_product_payloads, resolve_push_skus
from db.master_relations import (
    build_parent_relation_fields,
    extract_relations_from_records,
    _parse_configurable_variations,
)
from db.models import MasterProduct, MasterProductAttributeValue
from magento.master_catalog_rows import _payload_to_snapshot_row


def test_resolve_product_structure_defaults():
    assert resolve_product_structure("shopify") == "flat"
    assert resolve_product_structure("magento") == "parent_children"
    assert resolve_product_structure("magento", capabilities={"product_structure": "flat"}) == "flat"


def test_flat_channel_push_skus_excludes_parent_shells(monkeypatch):
    import db.channel_exports as mod

    monkeypatch.setattr(mod, "parent_skus_with_children", lambda _session, skus: {"PARENT"} & set(skus))

    result = resolve_push_skus(
        object(),
        "shopify",
        skus=["PARENT", "CHILD-1"],
        only_assigned=False,
        product_structure="flat",
    )

    assert result == {"CHILD-1"}


def test_parent_child_channel_push_skus_expands_relations(monkeypatch):
    import db.channel_exports as mod

    monkeypatch.setattr(mod, "active_skus_for_channel", lambda *_a, **_k: {"PARENT"})
    monkeypatch.setattr(mod, "expand_skus_with_children", lambda _session, skus: set(skus) | {"CHILD-1"})
    monkeypatch.setattr(mod, "expand_skus_with_parents", lambda _session, skus: set(skus) | {"PARENT"})

    result = resolve_push_skus(
        object(),
        "magento",
        skus=None,
        only_assigned=True,
        product_structure="parent_children",
    )

    assert result == {"PARENT", "CHILD-1"}


def test_explicit_sku_list_does_not_expand_relations(monkeypatch):
    import db.channel_exports as mod

    def _fail_expand(*_args, **_kwargs):
        raise AssertionError("expand_skus_with_children should not run for explicit SKU lists")

    monkeypatch.setattr(mod, "expand_skus_with_children", _fail_expand)
    monkeypatch.setattr(mod, "expand_skus_with_parents", _fail_expand)

    result = resolve_push_skus(
        object(),
        "magento",
        skus=["ASM-1", "ASM-2"],
        only_assigned=False,
        product_structure="parent_children",
    )

    assert result == {"ASM-1", "ASM-2"}


def test_explicit_sku_list_can_opt_in_to_expansion(monkeypatch):
    import db.channel_exports as mod

    monkeypatch.setattr(mod, "expand_skus_with_children", lambda _session, skus: set(skus) | {"CHILD-RTA"})
    monkeypatch.setattr(mod, "expand_skus_with_parents", lambda _session, skus: set(skus))

    result = resolve_push_skus(
        object(),
        "magento",
        skus=["ASM-1"],
        only_assigned=False,
        product_structure="parent_children",
        expand_relations=True,
    )

    assert result == {"ASM-1", "CHILD-RTA"}


def test_parent_child_channel_push_skus_expands_variation_builder_raw_children(monkeypatch):
    import db.channel_exports as mod

    monkeypatch.setattr(mod, "active_skus_for_channel", lambda *_a, **_k: {"PARENT"})
    monkeypatch.setattr(mod, "expand_skus_with_children", lambda _session, skus: set(skus))
    monkeypatch.setattr(mod, "expand_skus_with_parents", lambda _session, skus: set(skus))
    monkeypatch.setattr(
        mod,
        "_variation_builder_raw_children_maps",
        lambda _session, skus=None: ({"PARENT": ["CHILD-1", "CHILD-2"]}, {"CHILD-1": "PARENT", "CHILD-2": "PARENT"}),
    )

    result = resolve_push_skus(
        object(),
        "magento",
        skus=None,
        only_assigned=True,
        product_structure="parent_children",
    )

    assert result == {"PARENT", "CHILD-1", "CHILD-2"}


def test_extract_relations_from_variant_of():
    records = [
        {"sku": "CHILD-1", "payload": {"variant_of": "PARENT-1"}},
        {"sku": "PARENT-1", "payload": {"variant_list": "CHILD-1,CHILD-2", "product_type": "configurable"}},
    ]
    rows = extract_relations_from_records(records)
    keys = {(r["parent_sku"], r["child_sku"]) for r in rows}
    assert ("PARENT-1", "CHILD-1") in keys
    assert ("PARENT-1", "CHILD-2") in keys


def test_parse_configurable_variations_with_options():
    parsed = _parse_configurable_variations("sku=C1,width=30,color=White|sku=C2,width=36,color=Gray")
    assert parsed == [
        ("C1", {"width": "30", "color": "White"}),
        ("C2", {"width": "36", "color": "Gray"}),
    ]


def test_build_parent_relation_fields_maps_variation_axes_to_magento(monkeypatch):
    class FakeSession:
        pass

    session = FakeSession()
    from db import master_relations as mod

    monkeypatch.setattr(mod, "children_by_parent", lambda _session, parent_skus: {
        "PARENT": [
            {"child_sku": "C1", "option_mapping": {"variation_width_in": "12"}},
            {"child_sku": "C2", "option_mapping": {"variation_width_in": "15"}},
        ]
    })
    fields = build_parent_relation_fields(session, ["PARENT"])
    assert fields["PARENT"]["configurable_attributes"] == "width"
    assert fields["PARENT"]["configurable_variation_axis"] == "width"
    assert "width=Width" in fields["PARENT"]["configurable_variation_labels"]
    assert fields["PARENT"]["configurable_variations"] == "sku=C1,width=12|sku=C2,width=15"


def test_build_parent_relation_fields_from_session_like_rows(monkeypatch):
    class FakeSession:
        pass

    session = FakeSession()
    from db import master_relations as mod

    monkeypatch.setattr(
        mod,
        "children_by_parent",
        lambda _session, parent_skus: {
            "PARENT": [
                {"child_sku": "C1", "option_mapping": {"width": "30"}},
                {"child_sku": "C2", "option_mapping": {"width": "36"}},
            ]
        },
    )
    fields = build_parent_relation_fields(session, ["PARENT"])
    assert fields["PARENT"]["variant_list"] == "C1,C2"
    assert fields["PARENT"]["product_type"] == "configurable"
    assert "width" in fields["PARENT"]["configurable_attributes"]
    assert "sku=C1,width=30" in fields["PARENT"]["configurable_variations"]


def test_payload_to_snapshot_row_maps_title_and_categories():
    row = _payload_to_snapshot_row(
        {
            "sku": "SKU-1",
            "product_role": "standalone",
            "canonical_fields": {
                "title": "Wall Cabinet",
                "category_l1": "Kitchen",
                "category_l2": "Wall",
                "cabinet_door_style": "Shaker",
            },
            "price": 99.0,
        }
    )
    assert row["sku"] == "SKU-1"
    assert row["name"] == "Wall Cabinet"
    assert row["categories"] == "Kitchen/Wall"
    assert row["cabinet_door_style"] == "Shaker"
    assert row["price"] == 99.0


def test_payload_to_snapshot_row_retains_canonical_seo_title_after_alias_mapping():
    row = _payload_to_snapshot_row(
        {
            "sku": "SKU-SEO",
            "canonical_fields": {
                "title": "Master Name",
                "seo_title": "SEO Landing Title",
            },
            "fields": {"meta_title": "SEO Landing Title"},
        }
    )

    assert row["name"] == "Master Name"
    assert row["meta_title"] == "SEO Landing Title"
    assert row["seo_title"] == "SEO Landing Title"


def test_payload_to_snapshot_row_defaults_price_when_missing():
    row = _payload_to_snapshot_row(
        {
            "sku": "SKU-2",
            "product_role": "standalone",
            "canonical_fields": {"title": "No price row"},
        }
    )
    assert row["price"] == 1


def test_build_channel_product_payloads_falls_back_to_variation_builder_raw_children(catalog_intent_session):
    parent = MasterProduct(
        sku="ACH-B-PARENT",
        name="Anna Caramel Harvest Base",
        collection="Anna Caramel Harvest",
        status="active",
        row_hash="parent",
        raw_payload={
            "generated_by": "variation_builder",
            "option_attrs": ["variation_width_in", "variation_option_label"],
            "children": ["ACH-B12", "ACH-B15"],
            "group_values": {"collection": "Anna Caramel Harvest"},
        },
        is_active=True,
    )
    child_1 = MasterProduct(
        sku="ACH-B12",
        name="B12",
        collection="Anna Caramel Harvest",
        status="active",
        row_hash="c1",
        is_active=True,
    )
    child_2 = MasterProduct(
        sku="ACH-B15",
        name="B15",
        collection="Anna Caramel Harvest",
        status="active",
        row_hash="c2",
        is_active=True,
    )
    catalog_intent_session.add_all([parent, child_1, child_2])
    catalog_intent_session.flush()
    catalog_intent_session.add_all(
        [
            MasterProductAttributeValue(
                product_id=child_1.id,
                sku=child_1.sku,
                attribute_code="variation_width_in",
                value="12",
            ),
            MasterProductAttributeValue(
                product_id=child_2.id,
                sku=child_2.sku,
                attribute_code="variation_width_in",
                value="15",
            ),
        ]
    )
    catalog_intent_session.commit()

    payloads = build_channel_product_payloads(
        catalog_intent_session,
        "magento",
        skus=["ACH-B-PARENT", "ACH-B12", "ACH-B15"],
        only_assigned=False,
        product_structure="parent_children",
        prefer_projection_cache=False,
    )

    by_sku = {payload["sku"]: payload for payload in payloads}
    assert by_sku["ACH-B-PARENT"]["product_role"] == "parent"
    assert by_sku["ACH-B-PARENT"]["relation_fields"]["variant_list"] == "ACH-B12,ACH-B15"
    assert by_sku["ACH-B-PARENT"]["relation_fields"]["configurable_attributes"] == "width"
    assert "sku=ACH-B12,width=12" in by_sku["ACH-B-PARENT"]["relation_fields"]["configurable_variations"]
    assert by_sku["ACH-B12"]["product_role"] == "child"
    assert by_sku["ACH-B12"]["relation_fields"] == {"variant_of": "ACH-B-PARENT", "product_type": "simple"}
