from unittest.mock import MagicMock, patch

from db.channel_push_readiness import (
    _critical_attribute_checks,
    _is_pending_parent_shell_sku,
    _split_unmapped_masters,
)


def test_split_unmapped_masters_separates_configurable_parents():
    session = MagicMock()
    session.execute.return_value.all.return_value = [("ACH-BBC-PARENT",), ("ACH-BF-PARENT",)]

    unmapped = [
        {"master_sku": "ACH-BBC-PARENT", "name": "Parent A"},
        {"master_sku": "ACH-BF-PARENT", "name": "Parent B"},
        {"master_sku": "ACH-B12", "name": "Child simple"},
    ]
    parents_pending, truly_unlinked = _split_unmapped_masters(session, unmapped)

    assert [row["master_sku"] for row in parents_pending] == ["ACH-BBC-PARENT", "ACH-BF-PARENT"]
    assert [row["master_sku"] for row in truly_unlinked] == ["ACH-B12"]


def test_split_unmapped_masters_treats_parent_suffix_without_relation_rows():
    session = MagicMock()
    session.execute.return_value.all.return_value = []

    unmapped = [{"master_sku": "ACH-BBC-PARENT", "name": "Parent A"}]
    parents_pending, truly_unlinked = _split_unmapped_masters(session, unmapped)

    assert parents_pending == unmapped
    assert truly_unlinked == []


def test_is_pending_parent_shell_sku_suffix_heuristic():
    assert _is_pending_parent_shell_sku("ACH-BBC-PARENT", set())
    assert _is_pending_parent_shell_sku("ACH-BBC_PARENT", set())
    assert _is_pending_parent_shell_sku("ACH-BH-PARENT-2", set())
    assert _is_pending_parent_shell_sku("ACH-B-PARENT-2", set())
    assert not _is_pending_parent_shell_sku("ACH-B12", set())


def test_critical_attribute_checks_treats_base_image_as_media_push():
    session = MagicMock()
    with patch("db.channel_aliases.channel_aliases_by_canonical", return_value={}), patch(
        "db.master_static_field_mapping.static_alias_map_for_channel",
        return_value={
            "sku": "sku",
            "title": "name",
            "price": "price",
            "description": "description",
            "short_description": "short_description",
            "status": "status",
            "meta_title": "meta_title",
            "meta_description": "meta_description",
        },
    ), patch(
        "db.channel_attribute_options.channel_registry_codes_for",
        return_value={"sku", "name", "price", "description", "short_description", "status", "meta_title", "meta_description"},
    ):
        result = _critical_attribute_checks(session, "magento", magento_connection_id=1)

    assert "base_image" not in result["unmapped_critical"]
    assert result["critical_with_target"] == 9
    assert result["critical_mapped"] == 9


def test_critical_attribute_checks_treats_shopify_price_as_variant_push():
    session = MagicMock()
    mapping = {
        "sku": "sku",
        "title": "title",
        "description": "description",
        "short_description": "custom_short_description",
        "status": "status",
        "meta_title": "seo_title",
        "meta_description": "seo_description",
    }
    with patch("db.channel_aliases.channel_aliases_by_canonical", return_value={}), patch(
        "db.master_static_field_mapping.static_alias_map_for_channel", return_value=mapping
    ), patch(
        "db.channel_attribute_options.channel_registry_codes_for",
        return_value=set(mapping.values()) | {"sku"},
    ):
        result = _critical_attribute_checks(session, "shopify", shopify_connection_id=1)

    assert "price" not in result["unmapped_critical"]
    assert result["critical_with_target"] == 9
    assert result["critical_mapped"] == 9


def test_critical_attribute_checks_accepts_shopify_defaults_without_static_rows():
    session = MagicMock()
    with patch("db.channel_aliases.channel_aliases_by_canonical", return_value={}), patch(
        "db.master_static_field_mapping.static_alias_map_for_channel", return_value={}
    ), patch(
        "db.channel_attribute_options.channel_registry_codes_for",
        return_value={"sku", "title", "description", "status"},
    ):
        result = _critical_attribute_checks(session, "shopify", shopify_connection_id=1000001)

    assert result["unmapped_critical"] == []
    assert result["critical_mapped"] == 9


def test_critical_attribute_checks_accepts_legacy_shopify_seo_codes():
    session = MagicMock()
    mapping = {
        "sku": "sku",
        "title": "title",
        "description": "description",
        "short_description": "short_description",
        "status": "status",
        "meta_title": "meta_title",
        "meta_description": "meta_description",
    }
    with patch("db.channel_aliases.channel_aliases_by_canonical", return_value={}), patch(
        "db.master_static_field_mapping.static_alias_map_for_channel", return_value=mapping
    ), patch(
        "db.channel_attribute_options.channel_registry_codes_for",
        return_value={"sku", "title", "description", "status"},
    ):
        result = _critical_attribute_checks(session, "shopify", shopify_connection_id=1000001)

    assert result["unmapped_critical"] == []


def test_critical_attribute_checks_accepts_shopify_native_seo_and_short_description():
    session = MagicMock()
    mapping = {
        "sku": "sku",
        "title": "title",
        "price": "price",
        "description": "description",
        "short_description": "custom_short_description",
        "status": "status",
        "meta_title": "seo_title",
        "meta_description": "seo_description",
    }
    with patch("db.channel_aliases.channel_aliases_by_canonical", return_value={}), patch(
        "db.master_static_field_mapping.static_alias_map_for_channel", return_value=mapping
    ), patch(
        "db.channel_attribute_options.channel_registry_codes_for",
        return_value=set(mapping.values()),
    ):
        result = _critical_attribute_checks(session, "shopify", shopify_connection_id=1000001)

    assert result["unmapped_critical"] == []


def test_split_unmapped_masters_empty_input():
    session = MagicMock()
    parents_pending, truly_unlinked = _split_unmapped_masters(session, [])
    assert parents_pending == []
    assert truly_unlinked == []


def test_unmapped_partition_only_blocks_skus_present_in_remote_catalog():
    unmapped_rest = [
        {"master_sku": "ACH-B12", "in_remote_catalog": False},
        {"master_sku": "ACH-B15", "in_remote_catalog": True},
    ]
    pending_remote_creation = [item for item in unmapped_rest if not item.get("in_remote_catalog")]
    truly_unlinked = [item for item in unmapped_rest if item.get("in_remote_catalog")]
    assert [row["master_sku"] for row in pending_remote_creation] == ["ACH-B12"]
    assert [row["master_sku"] for row in truly_unlinked] == ["ACH-B15"]
