import pytest

from app.services.catalog.attributes import (
    build_attributes, normalise_key, normalise_value,
)


@pytest.mark.parametrize("raw,expected", [
    ("Colour", "color"), ("color", "color"), ("Shade", "color"),
    ("Size", "size"), ("size (uk)", "size"),
    ("Material", "material"), ("Fabric", "material"), ("Composition", "material"),
    ("Gender", "gender"), ("Department", "gender"),
    ("Flavour", "flavor"), ("Scent", "scent"),
    ("Some Custom Thing", "some_custom_thing"),
])
def test_normalise_key(raw, expected):
    assert normalise_key(raw) == expected


def test_shopify_title_placeholder_is_dropped():
    # "Title"/"Default Title" is Shopify's placeholder on single-variant
    # products. It appears on all 17 live products. Kept, every product gains a
    # meaningless attribute that inflates attribute count and quality_score.
    assert normalise_key("Title") is None


def test_shopify_seo_metafields_are_dropped():
    # title_tag and description_tag are SEO copy, not attributes, and would
    # inflate the attribute count that quality_score depends on.
    assert normalise_key("title_tag") is None
    assert normalise_key("description_tag") is None


def test_product_with_only_seo_metafields_has_no_attributes():
    attrs = build_attributes({
        "tags": [],
        "variants": [],
        "attributes_raw": [
            {"key": "title_tag", "value": "SEO title copy", "source": "metafield"},
            {"key": "description_tag",
             "value": "hidden snowboard winter sport snowboarding",
             "source": "metafield"},
        ],
    })
    assert attrs == []


@pytest.mark.parametrize("raw,expected", [
    ("Navy", "blue"), ("Midnight Navy", "blue"), ("Charcoal", "grey"),
    ("Ivory", "white"), ("Burgundy", "red"), ("Camel", "brown"),
    ("Black / White", "black"), ("Red, Blue", "red"),
])
def test_colour_maps_to_base_palette(raw, expected):
    value, unit = normalise_value("color", raw)
    assert value == expected


@pytest.mark.parametrize("raw,value,unit", [
    ("XS", "xs", "alpha"), ("Extra Small", "xs", "alpha"),
    ("M", "m", "alpha"), ("Large", "l", "alpha"), ("2XL", "xxl", "alpha"),
    ("UK 9", "9", "uk"), ("EU 43", "43", "eu"), ("10", "10", "numeric"),
])
def test_size_parses_system(raw, value, unit):
    assert normalise_value("size", raw) == (value, unit)


def test_measured_sizes_convert_to_a_base_unit():
    # 500ml and 0.5L must agree, or two identical products score as unrelated.
    assert normalise_value("size", "500ml") == normalise_value("size", "0.5 L")


@pytest.mark.parametrize("raw,expected", [
    ("Mens", "male"), ("Women", "female"), ("Ladies", "female"),
    ("Unisex", "unisex"), ("Kids", "kids"),
])
def test_gender_closed_set(raw, expected):
    value, _ = normalise_value("gender", raw)
    assert value == expected


def test_key_value_tags_parsed():
    attrs = build_attributes({
        "tags": ["material:leather", "color = Navy"],
        "variants": [], "attributes_raw": [],
    })
    by_key = {a["key"]: a for a in attrs}
    assert by_key["material"]["value"] == "leather"
    assert by_key["material"]["confidence"] == 0.9
    assert by_key["color"]["value"] == "blue"
    assert by_key["color"]["raw_value"] == "Navy"


def test_variant_options_become_attributes_but_title_does_not():
    attrs = build_attributes({
        "tags": [],
        "variants": [{"options": {"Title": "Default Title", "Color": "Navy"}}],
        "attributes_raw": [],
    })
    keys = {a["key"] for a in attrs}
    assert "color" in keys
    assert "title" not in keys


def test_metafield_beats_a_bare_tag_on_conflict():
    attrs = build_attributes({
        "tags": ["suede"],
        "variants": [],
        "attributes_raw": [{"key": "material", "value": "leather",
                            "source": "metafield"}],
    })
    material = [a for a in attrs if a["key"] == "material"]
    assert len(material) == 1
    assert material[0]["value"] == "leather"
    assert material[0]["source"] == "metafield"


def test_raw_value_is_always_preserved():
    attrs = build_attributes({
        "tags": [], "attributes_raw": [],
        "variants": [{"options": {"Color": "Midnight Navy"}}],
    })
    colour = next(a for a in attrs if a["key"] == "color")
    assert colour["raw_value"] == "Midnight Navy"
    assert colour["value"] == "blue"


def test_metafield_outranks_a_competing_key_value_tag():
    # Both sources produce a real "material" attribute with different values;
    # this exercises the second (by-key) dedupe pass, not just the case where
    # one side never becomes an attribute at all.
    attrs = build_attributes({
        "tags": ["material:suede"],
        "variants": [],
        "attributes_raw": [{"key": "material", "value": "leather",
                            "source": "metafield"}],
    })
    material = [a for a in attrs if a["key"] == "material"]
    assert len(material) == 1
    assert material[0]["value"] == "leather"
    assert material[0]["source"] == "metafield"


def test_unknown_source_degrades_instead_of_raising():
    attrs = build_attributes({
        "tags": [],
        "variants": [],
        "attributes_raw": [{"key": "material", "value": "x",
                            "source": "computed_guess"}],
    })
    material = next(a for a in attrs if a["key"] == "material")
    assert material["value"] == "x"
