from contextlib import contextmanager

from app.jobs.push_magento_attributes import (
    expand_requested_field_codes,
    enqueue_magento_attribute_push,
    parse_field_filter,
    resolve_filtered_magento_skus,
    resolve_magento_attribute_selection,
)
from db.models import ChannelAttributeAlias, MagentoConnection, MasterProduct, MasterProductAttributeValue, MasterStaticFieldMapping


def test_resolve_magento_attribute_selection_maps_canonical_to_remote(catalog_intent_session):
    session = catalog_intent_session
    session.add(
        MasterStaticFieldMapping(
            master_attribute_code="title",
            master_label="Title",
            field_group="core",
            data_type="text",
            magento_attribute_code="name",
            is_active=True,
        )
    )
    session.add(
        ChannelAttributeAlias(
            channel_code="magento",
            canonical_code="drawer_box",
            channel_attribute_code="drawer_box",
            mapping_scope="dynamic",
            action="use_existing",
            is_active=True,
        )
    )
    session.commit()

    resolved = resolve_magento_attribute_selection(session, ["title", "drawer_box"])

    assert "name" in resolved["remote_codes"]
    assert "drawer_box" in resolved["remote_codes"]
    assert "title" in resolved["canonical_codes"]
    assert resolved["unresolved_codes"] == []


def test_resolve_magento_attribute_selection_reports_passthrough_codes_not_unresolved(catalog_intent_session):
    session = catalog_intent_session

    resolved = resolve_magento_attribute_selection(session, ["drawer_box"])

    assert resolved["remote_codes"] == ["drawer_box"]
    assert resolved["canonical_codes"] == ["drawer_box"]
    assert resolved["passthrough_codes"] == ["drawer_box"]
    assert resolved["unresolved_codes"] == []


def test_parse_field_filter_requires_code_value():
    parsed = parse_field_filter("cabinet_type=base cabinets")

    assert parsed["code"] == "cabinet_type"
    assert parsed["value"] == "base cabinets"
    assert parsed["normalized_value"] == "base cabinets"


def test_expand_requested_field_codes_supports_bundles_and_dedupes():
    expanded = expand_requested_field_codes(
        ["accessories", "drawer_slides"],
        ["materials", "essentials"],
    )

    assert "accessories" in expanded
    assert "manufacturer" in expanded
    assert "family" in expanded
    assert "collection_style" in expanded
    assert "depth" in expanded
    assert "materials_box" in expanded
    assert "materials_face_frame" in expanded
    assert expanded.count("drawer_slides") == 1


def test_expand_requested_field_codes_supports_content_bundle():
    expanded = expand_requested_field_codes([], ["content"])

    assert "description" in expanded
    assert "short_description" in expanded
    assert "additional_information" in expanded
    assert "materials" in expanded


def test_resolve_filtered_magento_skus_matches_derived_canonical_fields(catalog_intent_session, monkeypatch):
    session = catalog_intent_session
    product = MasterProduct(
        sku="ACH-B12",
        name="Base Cabinet",
        row_hash="h1",
        is_active=True,
    )
    session.add(product)
    session.flush()
    session.add_all(
        [
            MasterProductAttributeValue(
                product_id=product.id,
                sku=product.sku,
                attribute_code="cabinet_type_sub_category_1",
                value="Base",
            ),
            MasterProductAttributeValue(
                product_id=product.id,
                sku=product.sku,
                attribute_code="cabinet_type_sub_category_2",
                value="Drawer Base Cabinet",
            ),
        ]
    )
    session.commit()

    monkeypatch.setattr("db.channel_exports._image_fields", lambda _session, _skus: {})
    monkeypatch.setattr("db.channel_exports.overrides_for_channel", lambda _session, _channel: {})
    monkeypatch.setattr("db.channel_exports._build_alias_map", lambda _session, _channel: {})
    monkeypatch.setattr(
        "db.channel_exports._attach_channel_skus",
        lambda _session, _channel, payloads, connection_id=None: [
            payload.setdefault("channel_sku", payload["sku"]) for payload in payloads
        ],
    )
    monkeypatch.setattr(
        "db.channel_exports._attach_association_fields",
        lambda _session, _channel, payloads, connection_id=None: None,
    )

    result = resolve_filtered_magento_skus(
        session,
        ["cabinet_type=base cabinets", "base_cabinets=drawer base cabinet"],
    )

    assert result["filters"] == [
        {"code": "cabinet_type", "value": "base cabinets"},
        {"code": "base_cabinets", "value": "drawer base cabinet"},
    ]
    assert result["matched_skus"] == ["ACH-B12"]


def test_resolve_filtered_magento_skus_returns_empty_when_no_match(catalog_intent_session, monkeypatch):
    session = catalog_intent_session
    product = MasterProduct(
        sku="ACH-W2430",
        name="Wall Cabinet",
        row_hash="h2",
        is_active=True,
    )
    session.add(product)
    session.flush()
    session.add_all(
        [
            MasterProductAttributeValue(
                product_id=product.id,
                sku=product.sku,
                attribute_code="cabinet_type_sub_category_1",
                value="Wall",
            ),
            MasterProductAttributeValue(
                product_id=product.id,
                sku=product.sku,
                attribute_code="cabinet_type_sub_category_2",
                value="Corner Wall Cabinet",
            ),
        ]
    )
    session.commit()

    monkeypatch.setattr("db.channel_exports._image_fields", lambda _session, _skus: {})
    monkeypatch.setattr("db.channel_exports.overrides_for_channel", lambda _session, _channel: {})
    monkeypatch.setattr("db.channel_exports._build_alias_map", lambda _session, _channel: {})
    monkeypatch.setattr(
        "db.channel_exports._attach_channel_skus",
        lambda _session, _channel, payloads, connection_id=None: [
            payload.setdefault("channel_sku", payload["sku"]) for payload in payloads
        ],
    )
    monkeypatch.setattr(
        "db.channel_exports._attach_association_fields",
        lambda _session, _channel, payloads, connection_id=None: None,
    )

    result = resolve_filtered_magento_skus(
        session,
        ["cabinet_type=base cabinets"],
    )

    assert result["matched_skus"] == []


def test_enqueue_magento_attribute_push_disables_option_sync_by_default(catalog_intent_session, monkeypatch):
    session = catalog_intent_session
    session.add(
        MagentoConnection(
            store_base_url="https://example.test",
            environment="staging",
            consumer_key="k",
            consumer_secret="s",
            access_token="t",
            access_token_secret="ts",
            status="active",
        )
    )
    session.commit()

    @contextmanager
    def fake_session():
        yield session

    class _FakeQueueRepo:
        def __init__(self, _session):
            self.enqueued = None

        def enqueue(self, connection_id, label, *, options=None, supersede_queued=False):
            self.enqueued = {
                "connection_id": connection_id,
                "label": label,
                "options": options or {},
                "supersede_queued": supersede_queued,
            }
            return 999

    fake_repo = _FakeQueueRepo(session)

    monkeypatch.setattr("app.jobs.push_magento_attributes.get_session", fake_session)
    monkeypatch.setattr(
        "db.magento_repositories.SqlAlchemyMagentoSyncQueueRepository",
        lambda _session: fake_repo,
    )
    monkeypatch.setattr(
        "app.jobs.push_channel_sample._wait_for_magento_queue",
        lambda queue_id, timeout=0, run_worker=False: {"status": "done", "queue_id": queue_id},
    )

    result = enqueue_magento_attribute_push(
        field_codes=["door_style"],
        skus=["ACH-B12"],
        filters=None,
        dry_run=False,
        connection_id=1,
        wait=False,
        run_worker=False,
        wait_timeout=10,
        sync_options_from_master=False,
    )

    assert result["status"] == "queued"
    assert result["queue_id"] == 999
    assert fake_repo.enqueued is not None
    assert fake_repo.enqueued["options"]["selected_attribute_codes"] == ["door_style"]
    assert fake_repo.enqueued["options"]["sync_options_from_master"] is False
    assert fake_repo.enqueued["options"]["allow_parallel_with_newer_queue_items"] is True
    assert fake_repo.enqueued["supersede_queued"] is False
