from db.models import MasterProduct, MasterProductRelation
from app.jobs.repair_variation_parent_names import (
    _custom_attribute_value,
    clean_variation_parent_name,
    fetch_magento_current_parent_names,
    find_parent_name_push_candidates,
    find_parent_name_repair_candidates,
)


def _parent(sku, name):
    product = MasterProduct()
    product.id = 1
    product.sku = sku
    product.name = name
    product.raw_payload = {"generated_by": "variation_builder"}
    product.is_active = True
    return product


def _relation(parent_sku, child_sku, mapping, sort_order=0):
    relation = MasterProductRelation()
    relation.parent_sku = parent_sku
    relation.child_sku = child_sku
    relation.option_mapping = mapping
    relation.sort_order = sort_order
    relation.source_label = "variation_builder"
    return relation


def test_clean_variation_parent_name_removes_composite_option_label():
    product = _parent(
        "MSW-WOCD-PARENT",
        "Snow White (height 30-42, variation_option_label (24 in W x 30 in H x 12 in D))",
    )
    relations = [
        _relation("MSW-WOCD-PARENT", "C1", {"height": "30", "variation_option_label": "24 x 30"}),
        _relation("MSW-WOCD-PARENT", "C2", {"height": "42", "variation_option_label": "24 x 42"}),
    ]

    cleaned = clean_variation_parent_name(product, relations)

    assert cleaned == "Snow White (Height 30\u201342)"
    assert "variation_option_label" not in cleaned


def test_find_candidates_skips_clean_names_by_default(monkeypatch):
    product = _parent("MSW-WOCD-PARENT", "Snow White (Height 30\u201342)")
    relations = [
        _relation("MSW-WOCD-PARENT", "C1", {"height": "30"}),
        _relation("MSW-WOCD-PARENT", "C2", {"height": "42"}),
    ]

    import app.jobs.repair_variation_parent_names as mod

    class FakeScalars:
        def __init__(self, rows):
            self._rows = rows

        def all(self):
            return self._rows

    class FakeSession:
        def scalars(self, stmt):
            return FakeScalars([product])

    monkeypatch.setattr(mod, "_relations_by_parent", lambda _session, _skus: {product.sku: relations})

    candidates = find_parent_name_repair_candidates(FakeSession())

    assert candidates == []


def test_find_push_candidates_includes_clean_current_db_names(monkeypatch):
    product = _parent("MSW-WOCD-PARENT", "Snow White (Height 30\u201342)")
    relations = [
        _relation("MSW-WOCD-PARENT", "C1", {"height": "30"}),
        _relation("MSW-WOCD-PARENT", "C2", {"height": "42"}),
    ]

    import app.jobs.repair_variation_parent_names as mod

    class FakeScalars:
        def __init__(self, rows):
            self._rows = rows

        def all(self):
            return self._rows

    class FakeSession:
        def scalars(self, stmt):
            return FakeScalars([product])

    monkeypatch.setattr(mod, "_relations_by_parent", lambda _session, _skus: {product.sku: relations})

    candidates = find_parent_name_push_candidates(FakeSession())

    assert len(candidates) == 1
    assert candidates[0].sku == "MSW-WOCD-PARENT"
    assert candidates[0].new_name == "Snow White (Height 30\u201342)"
    assert candidates[0].new_url_key == "snow-white-height-30-42-msw-wocd-parent"
    assert candidates[0].reason == "push_current_db_name"


def test_custom_attribute_value_extracts_magento_url_key():
    product = {
        "custom_attributes": [
            {"attribute_code": "url_key", "value": "snow-white-msw-wocd-parent"},
            {"attribute_code": "meta_title", "value": "Snow White"},
        ]
    }

    assert _custom_attribute_value(product, "url_key") == "snow-white-msw-wocd-parent"
    assert _custom_attribute_value(product, "missing") is None


def test_fetch_magento_current_parent_names_uses_channel_sku_mapping(monkeypatch):
    import app.jobs.repair_variation_parent_names as mod

    class _FakeConnRepo:
        def __init__(self, _session):
            pass

        def get_for_sync(self, _connection_id):
            return {
                "magento_api_base_url": "https://example.test/rest",
                "rest_base_path": "V1",
                "consumer_key": "k",
                "consumer_secret": "s",
                "access_token": "t",
                "access_token_secret": "ts",
                "signature_method": "HMAC-SHA256",
            }

    class _FakeApi:
        def __init__(self, _oauth):
            self.requested = []

        def get_product(self, sku):
            self.requested.append(sku)
            return {"name": "Parent", "custom_attributes": []}

    fake_api = _FakeApi(None)

    monkeypatch.setattr(
        "app.jobs.repair_variation_parent_names.channel_sku_for_master",
        lambda *args, **kwargs: "MAG-ACH-B-PARENT",
    )
    monkeypatch.setattr(
        "db.magento_repositories.SqlAlchemyMagentoConnectionRepository",
        _FakeConnRepo,
    )
    monkeypatch.setattr(
        "magento.magento_api.MagentoRestClient",
        lambda oauth: fake_api,
    )

    candidate = mod.ParentNameRepairCandidate(
        sku="ACH-B-PARENT",
        old_name="Old",
        new_name="New",
        old_url_key="old",
        new_url_key="new",
        child_count=2,
        reason="push_current_db_name",
    )

    result = fetch_magento_current_parent_names(object(), 1, [candidate])

    assert fake_api.requested == ["MAG-ACH-B-PARENT"]
    assert result["products"][0]["channel_sku"] == "MAG-ACH-B-PARENT"


def test_fetch_magento_current_parent_names_falls_back_to_remote_id_search(monkeypatch):
    import app.jobs.repair_variation_parent_names as mod

    class _FakeConnRepo:
        def __init__(self, _session):
            pass

        def get_for_sync(self, _connection_id):
            return {
                "magento_api_base_url": "https://example.test/rest",
                "rest_base_path": "V1",
                "consumer_key": "k",
                "consumer_secret": "s",
                "access_token": "t",
                "access_token_secret": "ts",
                "signature_method": "HMAC-SHA256",
            }

    class _FakeApi:
        def __init__(self, _oauth):
            self.requested = []

        def get_product(self, sku):
            self.requested.append(("get_product", sku))
            return None

        def search_products(self, *, sku=None, entity_id=None, page_size=20):
            self.requested.append(("search_products", sku, entity_id))
            if entity_id == 11824:
                return 200, [{"sku": "ACH-B-PARENT", "name": "Parent", "custom_attributes": []}], None
            return 200, [], None

    class _FakeSession:
        def scalar(self, stmt):
            text = str(stmt)
            if "channel_sku_mapping.remote_id" in text:
                return None
            if "magento_catalog_state.magento_product_id" in text:
                return 11824
            return None

    fake_api = _FakeApi(None)

    monkeypatch.setattr(
        "app.jobs.repair_variation_parent_names.channel_sku_for_master",
        lambda *args, **kwargs: "ACH-B-PARENT",
    )
    monkeypatch.setattr(
        "db.magento_repositories.SqlAlchemyMagentoConnectionRepository",
        _FakeConnRepo,
    )
    monkeypatch.setattr(
        "magento.magento_api.MagentoRestClient",
        lambda oauth: fake_api,
    )

    candidate = mod.ParentNameRepairCandidate(
        sku="ACH-B-PARENT",
        old_name="Old",
        new_name="New",
        old_url_key="old",
        new_url_key="new",
        child_count=2,
        reason="push_current_db_name",
    )

    result = fetch_magento_current_parent_names(_FakeSession(), 1, [candidate])

    assert result["products"][0]["magento_found"] is True
    assert result["products"][0]["lookup_method"] == "search_entity_id"
    assert ("search_products", None, 11824) in fake_api.requested
