from __future__ import annotations

import html
import re

from typing import Any, Callable, Dict, Iterable, Optional

from db.source_imports import normalize_column_key

CompositeDeriver = Callable[[Dict[str, Any]], Optional[str]]

_COMPOSITE_ATTRIBUTE_DERIVERS: Dict[str, CompositeDeriver] = {
    "accessories": lambda fields: _canonical_accessories(fields),
    "additional_information": lambda fields: _canonical_additional_information_html(fields),
    "angle": lambda fields: _canonical_angle(fields),
    "base_cabinets": lambda fields: _canonical_base_cabinets(fields),
    "box_construction": lambda fields: _canonical_box_construction(fields),
    "cabinet_type": lambda fields: _canonical_cabinet_type(fields),
    "care_instructions": lambda fields: _canonical_care_instructions(fields),
    "color_finish": lambda fields: _canonical_color_finish(fields),
    "collection_style": lambda fields: _canonical_collection_style(fields),
    "drawer_box": lambda fields: _canonical_drawer_box(fields),
    "drawer_slides": lambda fields: _canonical_drawer_slides(fields),
    "description": lambda fields: _canonical_description_html(fields),
    "finish_type": lambda fields: _canonical_finish_type(fields),
    "hinges": lambda fields: _canonical_hinges(fields),
    "materials": lambda fields: _canonical_materials_html(fields),
    "materials_box": lambda fields: _canonical_materials_box(fields),
    "materials_face_frame": lambda fields: _canonical_materials_face_frame(fields),
    "mouldings": lambda fields: _canonical_mouldings(fields),
    "overlay": lambda fields: _canonical_overlay_remote(fields),
    "panels_and_fillers": lambda fields: _canonical_panels_and_fillers(fields),
    "shelf_clips": lambda fields: _canonical_shelf_clips(fields),
    "shelves_included": lambda fields: _canonical_shelves_included(fields),
    "soft_close": lambda fields: _canonical_soft_close(fields),
    "packaged_dimension_depth": lambda fields: _canonical_packaged_dimension_depth(fields),
    "packaged_dimension_height": lambda fields: _canonical_packaged_dimension_height(fields),
    "packaged_dimension_width": lambda fields: _canonical_packaged_dimension_width(fields),
    "packaged_gross_weight": lambda fields: _canonical_packaged_gross_weight(fields),
    "warranty": lambda fields: _canonical_warranty(fields),
    "wall_cabinets": lambda fields: _canonical_wall_cabinets(fields),
}


def canonicalize_attribute_fields(fields: Dict[str, Any]) -> Dict[str, Any]:
    """Normalize master canonical fields used across channel payloads and storefront filters."""
    out = dict(fields)

    assembly = _canonical_assembly(out.get("assembly_type") or out.get("assembled_or_rta"))
    if assembly:
        out["assembly_type"] = assembly

    door_style = _canonical_door_style(out.get("cabinet_door_style") or out.get("door_style"))
    if door_style:
        out["cabinet_door_style"] = door_style
        out.setdefault("door_style", door_style)

    availability = _canonical_item_availability(out)
    if availability:
        out["item_availability"] = availability
        out.setdefault("collection_availability", availability)

    collection = _canonical_collection(out)
    if collection:
        out["collection"] = collection

    construction = _canonical_cabinet_construction(out.get("cabinet_construction_type"))
    if construction:
        out["cabinet_construction"] = construction

    overlay = _canonical_overlay(out.get("cabinet_door_overlay"))
    if overlay:
        out["cabinet_door_overlay"] = overlay

    color = _canonical_color(
        out.get("collection_color")
        or out.get("cabinet_style_color")
        or out.get("product_category_color")
        or out.get("color")
    )
    if color:
        out["color"] = color

    frame = _canonical_frame(out.get("frame"))
    if frame:
        out["frame"] = frame

    glass = _canonical_glass(out.get("glass"))
    if glass:
        out["glass"] = glass

    depth = _canonical_depth(out)
    if depth:
        out["depth"] = depth

    _apply_composite_attribute_derivations(out)

    return out


def composite_attribute_codes() -> set[str]:
    return set(_COMPOSITE_ATTRIBUTE_DERIVERS.keys())


def derive_composite_attribute_value(attribute_code: str, fields: Dict[str, Any]) -> Optional[str]:
    code = normalize_column_key(attribute_code)
    deriver = _COMPOSITE_ATTRIBUTE_DERIVERS.get(code)
    if deriver is None:
        return None
    return deriver(fields)


def matches_publish_constraints(fields: Dict[str, Any], constraints: Optional[Dict[str, Iterable[Any]]]) -> bool:
    """Return whether canonical fields satisfy channel/connection publish constraints."""
    if not constraints:
        return True
    normalized_fields = {normalize_column_key(code): value for code, value in fields.items()}
    for raw_code, allowed_values in constraints.items():
        code = normalize_column_key(raw_code)
        allowed = {_norm(value) for value in allowed_values or [] if _norm(value)}
        if not allowed:
            continue
        if _norm(normalized_fields.get(code)) not in allowed:
            return False
    return True


def _canonical_assembly(value: Any) -> Optional[str]:
    text = _norm(value)
    if not text:
        return None
    if text in {
        "rta",
        "ready to assemble",
        "ready-to-assemble",
        "unassembled",
        "unassembled/rta",
    } or "unassembled" in text:
        return "Ready-to-Assemble"
    if text == "assembled":
        return "Assembled"
    return str(value).strip()


def _canonical_door_style(value: Any) -> Optional[str]:
    text = _norm(value)
    if not text:
        return None
    aliases = {
        "shaker": "Shaker",
        "slim shaker": "Slim Shaker",
        "recessed panel": "Recessed Panel",
        "wide rail": "Wide Rail",
        "raised panel": "Raised Panel",
        "raisedpanel": "Raised Panel",
        "flat panel": "Flat Panel",
        "slab": "Slab",
    }
    return aliases.get(text, str(value).strip())


def _canonical_item_availability(fields: Dict[str, Any]) -> Optional[str]:
    explicit = fields.get("item_availability") or fields.get("collection_availability")
    if explicit:
        text = _norm(explicit)
        aliases = {
            "grab go": "Grab & Go",
            "grab and go": "Grab & Go",
            "available": "Available",
            "in stock": "Available",
            "special order": "Special Order",
        }
        return aliases.get(text, str(explicit).strip())
    if _truthy(fields.get("grab_n_go") or fields.get("grab_ngo") or fields.get("grab_go")):
        return "Grab & Go"
    stocked = fields.get("stocked")
    if stocked is not None and str(stocked).strip():
        return "Available" if _truthy(stocked) else "Special Order"
    return None


def _canonical_cabinet_construction(value: Any) -> Optional[str]:
    text = _norm(value)
    if not text:
        return None
    if "frameless" in text:
        return "Frameless"
    if "framed" in text:
        return "Framed"
    if "inset" in text:
        return "Inset Cabinets"
    return str(value).strip()


def _canonical_overlay(value: Any) -> Optional[str]:
    text = _norm(value)
    if not text:
        return None
    aliases = {
        "full overlay": "Full Overlay",
        "partial overlay": "Partial Overlay",
        "inset": "Inset Cabinets",
    }
    return aliases.get(text, str(value).strip())


def _canonical_color(value: Any) -> Optional[str]:
    text = _norm(value)
    if not text:
        return None
    aliases = {
        "gray": "Grey",
        "grey": "Grey",
        "stone gray": "Grey",
        "slate": "Grey",
        "mist": "Grey",
        "white": "White",
        "snow white": "White",
        "pearl white": "White",
        "blue": "Blue",
        "ocean blue": "Blue",
        "brown": "Brown",
        "caramel": "Brown",
        "espresso": "Brown",
        "beige": "Beige",
        "sandstone": "Beige",
        "black": "Black",
    }
    return aliases.get(text, str(value).strip())


def _canonical_frame(value: Any) -> Optional[str]:
    text = _norm(value)
    if not text:
        return None
    aliases = {
        "double hung": "Double Hung",
        "doublehung": "Double Hung",
        "slider": "Slider",
        "sliding": "Slider",
    }
    return aliases.get(text, str(value).strip())


def _canonical_glass(value: Any) -> Optional[str]:
    text = _norm(value)
    if not text:
        return None
    aliases = {
        "clear": "Clear Glass",
        "clear glass": "Clear Glass",
        "frosted": "Frosted Glass",
        "frosted glass": "Frosted Glass",
        "tempered": "Tempered Glass",
        "tempered glass": "Tempered Glass",
        "grid": "Grids",
        "grids": "Grids",
        "grille": "Grids",
        "grilles": "Grids",
    }
    return aliases.get(text, str(value).strip())


def _apply_composite_attribute_derivations(fields: Dict[str, Any]) -> None:
    for code, deriver in _COMPOSITE_ATTRIBUTE_DERIVERS.items():
        value = deriver(fields)
        if value:
            fields[code] = value
        else:
            fields.pop(code, None)


def _canonical_drawer_box(fields: Dict[str, Any]) -> Optional[str]:
    existing = _clean(fields.get("drawer_box"))
    if existing:
        return existing

    construction = _clean(fields.get("drawer_box_construction") or fields.get("drawer_box_construction_type"))
    preferred_material = _clean(
        fields.get("drawer_box_material")
        or fields.get("drawer_box_side_material")
        or fields.get("drawer_box_side_material_type")
    )
    material = preferred_material or _clean(fields.get("drawer_box_bottom_material"))

    joined = " ".join(part for part in (construction, material) if part)
    norm_joined = _norm(joined)
    norm_material = _norm(material)

    if "dovetail" in norm_joined and "solid wood" in norm_joined:
        if '3/4' in joined or "0.75" in norm_joined:
            return '3/4" Solid Wood Dovetail'
        return "Dovetail Solid Wood"
    if "metal" in norm_joined:
        return "Metal Sided"
    if "particle board" in norm_joined or "particleboard" in norm_joined:
        return "Particle Board"
    if "plywood" in norm_joined:
        return "Plywood"

    if construction and material:
        if norm_material in {"solid wood", "wood"}:
            return f"{construction} Solid Wood"
        return f"{construction} {material}"
    if material:
        return material
    if construction:
        return construction
    return None


def _canonical_accessories(fields: Dict[str, Any]) -> Optional[str]:
    if _canonical_cabinet_type(fields) == "accessories":
        return None

    existing = _normalize_accessory_label(fields.get("accessories"))
    if existing:
        return existing

    detail = _detail_value_for_group(fields, "accessories")
    normalized_detail = _normalize_accessory_label(detail)
    if normalized_detail:
        return normalized_detail

    haystacks = [
        fields.get("title"),
        fields.get("name"),
        fields.get("display_name"),
        fields.get("description"),
        fields.get("short_description"),
    ]
    joined = " ".join(str(value or "") for value in haystacks)
    return _normalize_accessory_label(joined)


def _canonical_additional_information_html(fields: Dict[str, Any]) -> Optional[str]:
    existing = _clean(fields.get("additional_information"))
    if existing:
        return _normalize_html_block(existing)

    rows = [
        ("Manufacturer", _clean(fields.get("manufacturer"))),
        ("Family", _clean(fields.get("family")) or _clean(fields.get("product_family"))),
        ("Collection Style", _clean(fields.get("collection_style")) or _clean(fields.get("collection"))),
        ("Warranty", _canonical_warranty(fields)),
        ("Care Instructions", _canonical_care_instructions(fields)),
        ("Package Height (in)", _canonical_packaged_dimension_height(fields)),
        ("Package Width (in)", _canonical_packaged_dimension_width(fields)),
        ("Package Length (in)", _canonical_packaged_dimension_depth(fields)),
        ("Package Weight (lb)", _canonical_packaged_gross_weight(fields)),
        ("Soft Close", _canonical_soft_close(fields)),
        ("Shelves Included", _canonical_shelves_included(fields)),
        ("Assembly Type", _clean(fields.get("assembly_type"))),
    ]
    return _build_definition_list_html(rows)


def _canonical_angle(fields: Dict[str, Any]) -> Optional[str]:
    for code in ("angle", "variation_angle", "angle_direction"):
        normalized = _normalize_angle_label(fields.get(code))
        if normalized:
            return normalized

    haystacks = [
        fields.get("title"),
        fields.get("name"),
        fields.get("display_name"),
        fields.get("description"),
        fields.get("short_description"),
        fields.get("cabinet_type_sub_category_2"),
    ]
    joined = " ".join(str(value or "") for value in haystacks)
    return _normalize_angle_label(joined)


def _canonical_description_html(fields: Dict[str, Any]) -> Optional[str]:
    existing = _clean(fields.get("description"))
    if existing:
        base_html = _normalize_html_block(existing)
    else:
        paragraph_source = _first_clean(
            fields,
            "cabinet_description",
            "cabinet_style_short_description",
            "short_description",
        )
        if not paragraph_source:
            return None
        base_html = _paragraphize_text(paragraph_source)

    bullets = _description_feature_bullets(fields)
    if not bullets:
        return base_html
    return f"{base_html}\n{_unordered_list_html(bullets)}".strip()


def _canonical_base_cabinets(fields: Dict[str, Any]) -> Optional[str]:
    return _canonical_group_detail(fields, "base_cabinets", "base cabinets", _normalize_base_cabinet_label)


def _canonical_box_construction(fields: Dict[str, Any]) -> Optional[str]:
    existing = _clean(fields.get("box_construction"))
    if existing:
        return existing

    source = fields.get("cabinet_construction") or fields.get("cabinet_construction_type")
    return _canonical_cabinet_construction(source)


def _canonical_materials_html(fields: Dict[str, Any]) -> Optional[str]:
    existing = _clean(fields.get("materials"))
    if existing:
        return _normalize_html_block(existing)

    rows = [
        ("Cabinet Exterior Side Finish", _clean(fields.get("cabinet_exterior_side_finish"))),
        ("Cabinet Back Material", _clean(fields.get("cabinet_back_material"))),
        ("Cabinet Bottom Material", _clean(fields.get("cabinet_bottom_material"))),
        ("Cabinet Top Material", _clean(fields.get("cabinet_top_material"))),
        ("Cabinet Carcass Material", _clean(fields.get("cabinet_carcass_material"))),
        ("Cabinet Toe Kick Construction", _clean(fields.get("cabinet_toe_kick_construction"))),
        ("Cabinet Interior Finish", _clean(fields.get("cabinet_interior_finish"))),
        ("Cabinet Corner Support", _clean(fields.get("cabinet_corner_support"))),
        ("Cabinet I-Beam Support Braces", _clean(fields.get("cabinet_i_beam_support_braces"))),
        ("Cabinet Shelf Material", _clean(fields.get("cabinet_shelf_material"))),
        ("Materials Box", _canonical_materials_box(fields)),
        ("Materials Face Frame", _canonical_materials_face_frame(fields)),
        ("Shelf Clips", _canonical_shelf_clips(fields)),
        ("Box Construction", _canonical_box_construction(fields)),
        ("Drawer Box", _canonical_drawer_box(fields)),
    ]
    return _build_definition_list_html(rows)


def _canonical_cabinet_type(fields: Dict[str, Any]) -> Optional[str]:
    for code in ("cabinet_type", "cabinet_type_sub_category_1"):
        normalized = _normalize_cabinet_type_label(fields.get(code))
        if normalized:
            return normalized
    return None


def _canonical_collection_style(fields: Dict[str, Any]) -> Optional[str]:
    existing = _clean(fields.get("collection_style"))
    if existing:
        return existing
    return _canonical_collection(fields)


def _canonical_care_instructions(fields: Dict[str, Any]) -> Optional[str]:
    for code in ("care_instructions", "product_care_instructions", "care_and_cleaning"):
        text = _clean_care_instructions(fields.get(code))
        if text:
            return text
    return None


def _canonical_color_finish(fields: Dict[str, Any]) -> Optional[str]:
    existing = _normalize_color_finish_label(fields.get("color_finish"))
    if existing:
        return existing

    for code in (
        "collection_color",
        "cabinet_style_color",
        "product_category_color",
        "color",
        "collection",
        "product_collection_series_name",
        "series_name",
        "title",
        "name",
        "display_name",
    ):
        normalized = _normalize_color_finish_label(fields.get(code))
        if normalized:
            return normalized
    return None


def _canonical_drawer_slides(fields: Dict[str, Any]) -> Optional[str]:
    for code in (
        "drawer_slides",
        "drawer_slide_type",
        "drawer_slides_type",
        "drawer_slide_glide",
        "drawer_guide_type",
        "drawer_glide_type",
    ):
        normalized = _normalize_drawer_slides_label(fields.get(code))
        if normalized:
            return normalized

    joined = " ".join(
        str(fields.get(code) or "")
        for code in ("title", "name", "display_name", "description", "short_description")
    )
    return _normalize_drawer_slides_label(joined)


def _canonical_finish_type(fields: Dict[str, Any]) -> Optional[str]:
    existing = _normalize_finish_type_label(fields.get("finish_type"))
    if existing:
        return existing

    finish = _first_clean(
        fields,
        "cabinet_door_finish_type",
        "cabinet_finish_type",
        "finish_type_name",
        "finish",
        "cabinet_exterior_side_finish",
        "cabinet_interior_finish",
    )
    color_finish = _canonical_color_finish(fields)
    normalized = _normalize_finish_type_label(finish, color_finish=color_finish)
    if normalized:
        return normalized
    return _normalize_finish_type_label(color_finish, color_finish=color_finish)


def _canonical_collection(fields: Dict[str, Any]) -> Optional[str]:
    return _first_clean(
        fields,
        "collection",
        "product_collection_series_name",
        "product_collection_series",
        "collection_series_name",
        "series_name",
    )


# Source codes that feed Magento select ``depth`` (master rarely stores code ``depth``).
DEPTH_OPTION_SOURCE_CODES: tuple[str, ...] = (
    "depth",
    "assembled_depth",
    "assembled_depth_in",
    "assembled_depth_inches",
    "variation_depth_in",
    "depth_in",
    "depth_inches",
    "depth_measurement",
)


def _canonical_depth(fields: Dict[str, Any]) -> Optional[str]:
    explicit = _normalize_measurement_value(fields.get("depth"))
    if explicit:
        return explicit

    assembly = _canonical_assembly(fields.get("assembly_type") or fields.get("assembled_or_rta"))
    codes = [
        "variation_depth_in",
        "depth_in",
        "depth_inches",
        "depth_measurement",
    ]
    if assembly == "Assembled":
        codes = [
            "assembled_depth",
            "assembled_depth_in",
            "assembled_depth_inches",
            *codes,
        ]
    for code in codes:
        normalized = _normalize_measurement_value(fields.get(code))
        if normalized:
            return normalized
    return None


def normalize_depth_option_label(value: Any) -> Optional[str]:
    """Normalize a raw master depth measurement to the Magento option label form."""
    return _normalize_measurement_value(value)


def _canonical_hinges(fields: Dict[str, Any]) -> Optional[str]:
    for code in ("hinges", "door_hinge_type", "hinge_type"):
        normalized = _normalize_hinges_label(fields.get(code))
        if normalized:
            return normalized
    return None


def _canonical_materials_box(fields: Dict[str, Any]) -> Optional[str]:
    existing = _normalize_materials_box_label(fields.get("materials_box"))
    if existing:
        return existing

    joined = " ".join(
        str(fields.get(code) or "")
        for code in (
            "drawer_box_material",
            "drawer_box_side_material",
            "drawer_box_bottom_material",
            "drawer_box_construction",
            "drawer_box_construction_type",
        )
    )
    return _normalize_materials_box_label(joined)


def _canonical_materials_face_frame(fields: Dict[str, Any]) -> Optional[str]:
    existing = _normalize_materials_face_frame_label(fields.get("materials_face_frame"))
    if existing:
        return existing

    joined = " ".join(
        str(fields.get(code) or "")
        for code in (
            "face_frame",
            "frame",
            "face_frame_material",
            "cabinet_face_frame_material",
            "materials_face_frame",
        )
    )
    return _normalize_materials_face_frame_label(joined)


def _canonical_mouldings(fields: Dict[str, Any]) -> Optional[str]:
    return _canonical_group_detail(fields, "mouldings", "mouldings", _normalize_generic_detail_label)


def _canonical_overlay_remote(fields: Dict[str, Any]) -> Optional[str]:
    existing = _normalize_overlay_label(fields.get("overlay"))
    if existing:
        return existing
    return _normalize_overlay_label(fields.get("cabinet_door_overlay"))


def _canonical_panels_and_fillers(fields: Dict[str, Any]) -> Optional[str]:
    return _canonical_group_detail(
        fields,
        "panels_and_fillers",
        "panels and fillers",
        _normalize_panels_and_fillers_label,
    )


def _canonical_wall_cabinets(fields: Dict[str, Any]) -> Optional[str]:
    return _canonical_group_detail(fields, "wall_cabinets", "wall cabinets", _normalize_wall_cabinet_label)


def _canonical_shelf_clips(fields: Dict[str, Any]) -> Optional[str]:
    for code in ("shelf_clips", "cabinet_shelf_clip_type", "shelf_clip_type"):
        normalized = _normalize_shelf_clips_label(fields.get(code))
        if normalized:
            return normalized
    return None


def _canonical_shelves_included(fields: Dict[str, Any]) -> Optional[str]:
    explicit = fields.get("shelves_included")
    if explicit is not None and str(explicit).strip():
        return "Yes" if _truthy(explicit) else "No"

    count = _parse_int(fields.get("number_of_shelves_included"))
    if count is not None:
        return "Yes" if count > 0 else "No"
    return None


def _canonical_soft_close(fields: Dict[str, Any]) -> Optional[str]:
    explicit = fields.get("soft_close")
    if explicit is not None and str(explicit).strip():
        return "Yes" if _truthy(explicit) else "No"

    for code, value in fields.items():
        normalized_code = normalize_column_key(code)
        if "soft_close" not in normalized_code and "softclose" not in normalized_code:
            continue
        if value is not None and str(value).strip():
            return "Yes" if _truthy(value) else "No"

    signals = [
        fields.get("door_hinge_type"),
        fields.get("hinges"),
        fields.get("drawer_slide_type"),
        fields.get("drawer_slides_type"),
        fields.get("drawer_slides"),
        fields.get("title"),
        fields.get("name"),
        fields.get("display_name"),
        fields.get("description"),
        fields.get("short_description"),
    ]
    for code, value in fields.items():
        normalized_code = normalize_column_key(code)
        if any(token in normalized_code for token in ("hinge", "slide", "drawer", "door", "soft_close", "softclose")):
            signals.append(value)
    haystack = _norm(" ".join(str(value or "") for value in signals))
    if not haystack:
        return None
    return "Yes" if "soft close" in haystack or "softclose" in haystack or "blum" in haystack else "No"


def _canonical_warranty(fields: Dict[str, Any]) -> Optional[str]:
    text = _clean(fields.get("warranty"))
    if text:
        return text

    warranty_type = _clean(fields.get("product_warranty"))
    length = _normalize_warranty_length(fields.get("warranty_length"))
    if warranty_type and length:
        type_norm = _norm(warranty_type)
        length_norm = _norm(length)
        if length_norm in type_norm:
            return warranty_type
        if type_norm in length_norm:
            return length
        return f"{length} {warranty_type}"
    if warranty_type:
        return warranty_type
    if not length:
        return None
    return f"{length} Warranty"


def _canonical_packaged_dimension_height(fields: Dict[str, Any]) -> Optional[str]:
    return _first_normalized_measurement(
        fields,
        "packaged_dimension_height",
        "package_height",
        "package_height_in",
        "package_height_inches",
    )


def _canonical_packaged_dimension_width(fields: Dict[str, Any]) -> Optional[str]:
    return _first_normalized_measurement(
        fields,
        "packaged_dimension_width",
        "package_width",
        "package_width_in",
        "package_width_inches",
    )


def _canonical_packaged_dimension_depth(fields: Dict[str, Any]) -> Optional[str]:
    return _first_normalized_measurement(
        fields,
        "packaged_dimension_depth",
        "package_length",
        "package_length_in",
        "package_length_inches",
        "package_depth",
        "package_depth_in",
        "package_depth_inches",
    )


def _canonical_packaged_gross_weight(fields: Dict[str, Any]) -> Optional[str]:
    return _first_normalized_measurement(
        fields,
        "packaged_gross_weight",
        "package_weight",
        "package_weight_lb",
        "package_weight_lbs",
        "gross_weight",
        "gross_weight_lb",
    )


def _canonical_group_detail(
    fields: Dict[str, Any],
    attribute_code: str,
    expected_group: str,
    normalizer: Callable[[Any], Optional[str]],
) -> Optional[str]:
    if _canonical_cabinet_type(fields) != expected_group:
        return None

    detail = _detail_value_for_group(fields, expected_group)
    exact_detail = _exact_group_detail_label(detail, expected_group)
    if exact_detail:
        return exact_detail

    exact_existing = _exact_group_detail_label(fields.get(attribute_code), expected_group)
    if exact_existing:
        return exact_existing

    existing = normalizer(fields.get(attribute_code))
    if existing:
        return existing
    return normalizer(detail)


def _detail_value_for_group(fields: Dict[str, Any], expected_group: str) -> Optional[str]:
    if _canonical_cabinet_type(fields) != expected_group:
        return None
    return _clean(
        fields.get("taxonomy_leaf_label")
        or fields.get("cabinet_type_sub_category_2")
        or fields.get("sub_type")
        or fields.get("product_type")
        or fields.get("type")
    )


def _exact_group_detail_label(value: Any, expected_group: str) -> Optional[str]:
    text = _clean(value)
    if not text:
        return None
    leaf = text.split(" / ")[-1].strip()
    if not leaf:
        return None
    normalized_leaf = _norm(leaf)
    if not normalized_leaf:
        return None
    blocked = {
        _norm(expected_group),
        _norm(expected_group.replace(" cabinets", "").replace(" and fillers", "")),
        "cabinet",
        "cabinets",
    }
    if normalized_leaf in blocked:
        return None
    return normalized_leaf


def _normalize_accessory_label(value: Any) -> Optional[str]:
    text = _clean(value)
    if not text:
        return None
    norm = _norm(text)
    patterns = (
        ("floating shelf", ("floating shelf",)),
        ("rollout tray", ("rollout tray", "roll out tray", "roll-out tray", "pull out tray", "pullout tray")),
        ("glass door", ("glass door", "loose glass door")),
        ("touch up", ("touch up", "touch-up", "touch up paint")),
        ("valance arch", ("valance arch",)),
        ("corbel", ("corbel",)),
        ("knee drawer", ("knee drawer",)),
        ("post", ("post",)),
    )
    padded = f" {norm} "
    for label, aliases in patterns:
        for alias in aliases:
            alias_norm = _norm(alias)
            if f" {alias_norm} " in padded:
                return label
    return None


def _normalize_angle_label(value: Any) -> Optional[str]:
    text = _clean(value)
    if not text:
        return None
    norm = _norm(text)
    aliases = (
        ("Upper Left", ("upper left", "top left")),
        ("Upper Right", ("upper right", "top right")),
        ("Lower Left", ("lower left", "bottom left")),
        ("Lower Right", ("lower right", "bottom right")),
        ("Left", ("left", "left hand", "left hinge", "left side")),
        ("Right", ("right", "right hand", "right hinge", "right side")),
        ("Up", ("up", "upper")),
        ("Down", ("down", "lower")),
    )
    padded = f" {norm} "
    for label, values in aliases:
        for candidate in values:
            candidate_norm = _norm(candidate)
            if f" {candidate_norm} " in padded:
                return label if label in {
                    "Left",
                    "Right",
                    "Up",
                    "Down",
                    "Upper Left",
                    "Upper Right",
                    "Lower Left",
                    "Lower Right",
                } else None
    return None


def _normalize_base_cabinet_label(value: Any) -> Optional[str]:
    text = _clean(value)
    if not text:
        return None
    norm = _norm(text)
    if "corner" in norm or "diagonal" in norm:
        return "corner"
    if "drawer" in norm:
        return "drawer"
    if "sink" in norm:
        return "sink"
    if "special" in norm:
        return "special"
    if "tall" in norm or "pantry" in norm:
        return "tall"
    if "base" in norm or "single door" in norm or "double door" in norm:
        return "basic base"
    return _normalize_generic_detail_label(text)


def _normalize_cabinet_type_label(value: Any) -> Optional[str]:
    text = _clean(value)
    if not text:
        return None
    from db.shopping_facet_catalog import magento_option_label

    normalized = magento_option_label(text)
    return normalized or None


def _normalize_color_finish_label(value: Any) -> Optional[str]:
    text = _clean(value)
    if not text:
        return None
    norm = _norm(text)
    aliases = {
        "anna caramel harvest": "Caramel Harvest",
        "caramel harvest": "Caramel Harvest",
        "harvest brown": "Harvest Brown",
        "anna stone gray": "Stone Gray",
        "stone gray": "Stone Gray",
        "gray": "Gray",
        "grey": "Gray",
        "anna snow white": "Snow White",
        "maya snow white": "Snow White",
        "grace snow white": "Snow White",
        "eleanor snow white": "Snow White",
        "snow white": "Snow White",
        "white": "White",
        "pewter white": "Pewter White",
        "navy blue": "Navy Blue",
        "navy": "Navy",
        "espresso": "Espresso",
        "pewter": "Pewter",
        "white oak rift cut and wire brushed": "White Oak - Rift-Cut & Wire-Brushed",
        "white oak rift cut wire brushed": "White Oak - Rift-Cut & Wire-Brushed",
    }
    if norm in aliases:
        return aliases[norm]
    for needle, label in aliases.items():
        if f" {needle} " in f" {norm} ":
            return label
    return None


def _normalize_drawer_slides_label(value: Any) -> Optional[str]:
    text = _clean(value)
    if not text:
        return None
    norm = _norm(text)
    if "blum" in norm:
        return "Blum Soft-Close Slides"
    if "ball bearing" in norm or "ball-bearing" in str(value or "").lower():
        return "Ball-Bearing Slides"
    if "standard side mount" in norm:
        return "Standard Side-Mount"
    if "side mount" in norm or "side-mount" in str(value or "").lower():
        return "Standard Side-Mount"
    if "undermount" in norm or "under mount" in norm or "full extension soft close" in norm:
        return "Undermount Slides"
    return None


def _normalize_finish_type_label(value: Any, *, color_finish: Optional[str] = None) -> Optional[str]:
    text = _clean(value)
    norm = _norm(text)
    color = _clean(color_finish)
    color_norm = _normalize_color_finish_label(color) if color else None
    if norm:
        if "wire brushed" in norm or "wire-brushed" in str(value or "").lower():
            return "White Oak - Rift-Cut & Wire-Brushed"
        if "paint" in norm:
            base = color_norm or _strip_finish_descriptors(text)
            return f"{base} Painted Finish".strip() if base else "Painted Finish"
        if "stain" in norm:
            base = color_norm or _strip_finish_descriptors(text)
            return f"{base} Stain Finish".strip() if base else "Stain Finish"
    if color_norm in {"Caramel Harvest", "Harvest Brown", "Espresso"}:
        return f"{color_norm} Stain Finish"
    if color_norm in {"White", "Gray", "Snow White", "Stone Gray"}:
        return f"{color_norm} Painted Finish"
    if color_norm == "White Oak - Rift-Cut & Wire-Brushed":
        return color_norm
    return None


def _normalize_generic_detail_label(value: Any) -> Optional[str]:
    text = _clean(value)
    if not text:
        return None
    return _norm(text)


def _normalize_panels_and_fillers_label(value: Any) -> Optional[str]:
    text = _clean(value)
    if not text:
        return None
    norm = _norm(text)
    if "filler" in norm:
        return "fillers"
    if "panel" in norm:
        return "panels"
    return _normalize_generic_detail_label(text)


def _normalize_wall_cabinet_label(value: Any) -> Optional[str]:
    text = _clean(value)
    if not text:
        return None
    norm = _norm(text)
    if "corner" in norm or "diagonal" in norm:
        return "corner wall"
    if "stack" in norm:
        return "stacked wall"
    if "bridge" in norm:
        return "bridge wall"
    if "special" in norm:
        return "special wall"
    if "wall" in norm or "glass door" in norm:
        return "basic wall"
    return _normalize_generic_detail_label(text)


def _normalize_hinges_label(value: Any) -> Optional[str]:
    text = _clean(value)
    if not text:
        return None
    norm = _norm(text)
    if "full overlay" in norm:
        return "Full Overlay Hinges"
    if "soft close" in norm or "soft-close" in str(value or "").lower() or "concealed" in norm:
        return "Concealed Soft-Close Hinges"
    return "Standard Hinges"


def _normalize_materials_box_label(value: Any) -> Optional[str]:
    text = _clean(value)
    if not text:
        return None
    norm = _norm(text)
    if "7/16" in text and "birch" in norm and "plywood" in norm:
        return '7/16" Birch Plywood Dovetail Box'
    if "5/8" in text and "solid wood" in norm:
        return '5/8" Solid Wood Dovetail Box'
    if "3/4" in text and "solid wood" in norm and "box" in norm:
        return '3/4" Solid Wood Dovetail Box'
    if "3/4" in text and "solid wood" in norm:
        return '3/4" Solid Wood Dovetail'
    if "wood and hdf" in norm or ("wood" in norm and "hdf" in norm):
        return "Wood and HDF"
    if "particle board" in norm or "particleboard" in norm:
        return "Particle Board"
    if "plywood" in norm:
        return "Plywood"
    return None


def _normalize_materials_face_frame_label(value: Any) -> Optional[str]:
    text = _clean(value)
    if not text:
        return None
    norm = _norm(text)
    if "hardwood" in norm and "3/4" in text and "1 1/2" in text:
        return '3/4" x 1 1/2" Hardwood'
    if "hardwood" in norm:
        return "Solid Wood"
    if "solid wood face frame" in norm and "3/4" in text and "1 1/2" in text:
        return '3/4" x 1 1/2" Solid Wood Face Frame'
    if "solid wood" in norm and "3/4" in text and "1 1/2" in text:
        return '3/4" x 1 1/2" Solid Wood'
    if "plywood" in norm:
        return "Plywood"
    if "solid wood" in norm:
        return "Solid Wood"
    return None


def _normalize_overlay_label(value: Any) -> Optional[str]:
    text = _clean(value)
    if not text:
        return None
    norm = _norm(text)
    if "full overlay" in norm:
        return "Full Overlay - Framed"
    if "partial overlay" in norm:
        return "Partial Overlay - Framed"
    if "inset" in norm:
        return "Inset"
    return None


def _normalize_shelf_clips_label(value: Any) -> Optional[str]:
    text = _clean(value)
    if not text:
        return None
    norm = _norm(text)
    if "stainless" in norm and "lock" in norm:
        return "Stainless Steel (locking)"
    if "plastic" in norm:
        return "Plastic"
    if "metal" in norm or "steel" in norm:
        return "Metal"
    return None


def _parse_int(value: Any) -> Optional[int]:
    text = _clean(value)
    if not text:
        return None
    digits = "".join(ch for ch in text if ch.isdigit())
    if not digits:
        return None
    try:
        return int(digits)
    except ValueError:
        return None


def _truthy(value: Any) -> bool:
    return _norm(value) in {"1", "true", "yes", "y", "available", "in stock", "grab go", "grab and go"}


def _normalize_warranty_length(value: Any) -> Optional[str]:
    text = _clean(value)
    if not text:
        return None
    norm = _norm(text)
    if "year" in norm:
        return text
    return f"{text} Year"


def _first_normalized_measurement(fields: Dict[str, Any], *codes: str) -> Optional[str]:
    for code in codes:
        normalized = _normalize_measurement_value(fields.get(code))
        if normalized:
            return normalized
    return None


def _first_clean(fields: Dict[str, Any], *codes: str) -> Optional[str]:
    for code in codes:
        text = _clean(fields.get(code))
        if text:
            return text
    return None


def _normalize_measurement_value(value: Any) -> Optional[str]:
    text = _clean(value)
    if not text:
        return None

    cleaned = (
        str(text)
        .replace('"', "")
        .replace("inches", "")
        .replace("inch", "")
        .replace("in.", "")
        .replace("in", "")
        .strip()
    )
    if not cleaned:
        return None

    mixed = re.fullmatch(r"(\d+)\s*[- ]\s*(\d+)\s*/\s*(\d+)", cleaned)
    if mixed:
        whole = int(mixed.group(1))
        numerator = int(mixed.group(2))
        denominator = int(mixed.group(3))
        if denominator:
            return _format_decimal_number(whole + (numerator / denominator))

    fraction = re.fullmatch(r"(\d+)\s*/\s*(\d+)", cleaned)
    if fraction:
        numerator = int(fraction.group(1))
        denominator = int(fraction.group(2))
        if denominator:
            return _format_decimal_number(numerator / denominator)

    number = re.search(r"\d+(?:\.\d+)?", cleaned)
    if not number:
        return None
    return _format_decimal_number(float(number.group(0)))


def _format_decimal_number(value: float) -> Optional[str]:
    if value != value:
        return None
    if float(value).is_integer():
        return str(int(value))
    return f"{value:.6f}".rstrip("0").rstrip(".")


def _strip_finish_descriptors(value: Any) -> Optional[str]:
    text = _clean(value)
    if not text:
        return None
    cleaned = str(text)
    cleaned = re.sub(r"\b(painted?|painting|stain(?:ed)?|finish)\b", " ", cleaned, flags=re.IGNORECASE)
    cleaned = " ".join(cleaned.split())
    return cleaned or None


def _clean_care_instructions(value: Any) -> Optional[str]:
    text = _clean(value)
    if not text:
        return None
    cleaned = re.sub(r"\s*can be modified in field\.?\s*$", "", text, flags=re.IGNORECASE).strip()
    return cleaned or None


def _build_definition_list_html(rows: Iterable[tuple[str, Optional[str]]]) -> Optional[str]:
    items = [
        f"<dt>{html.escape(label)}</dt><dd>{html.escape(value)}</dd>"
        for label, value in rows
        if _clean(value)
    ]
    if not items:
        return None
    return f"<dl>{''.join(items)}</dl>"


def _paragraphize_text(value: str) -> str:
    paragraphs = [segment.strip() for segment in re.split(r"(?:\r?\n){2,}", value) if segment.strip()]
    if not paragraphs:
        return f"<p>{html.escape(value.strip())}</p>"
    return "".join(f"<p>{html.escape(paragraph)}</p>" for paragraph in paragraphs)


def _unordered_list_html(items: Iterable[str]) -> str:
    rendered = [f"<li>{html.escape(str(item).strip())}</li>" for item in items if str(item).strip()]
    if not rendered:
        return ""
    return f"<ul>{''.join(rendered)}</ul>"


def _normalize_html_block(value: str) -> str:
    text = value.strip()
    if re.search(r"<[a-z][\s\S]*>", text, flags=re.IGNORECASE):
        return text
    return _paragraphize_text(text)


def _description_feature_bullets(fields: Dict[str, Any]) -> list[str]:
    bullets: list[str] = []

    overlay = _clean(fields.get("overlay"))
    if overlay:
        bullets.append(f"{overlay} doors provide a seamless aesthetic")

    if _canonical_soft_close(fields) == "Yes":
        bullets.append("Soft close doors and drawers help prevent slamming")

    drawer_slides = _clean(fields.get("drawer_slides"))
    if drawer_slides:
        bullets.append(f"{drawer_slides} support smooth drawer operation")

    hinges = _clean(fields.get("hinges"))
    if hinges:
        bullets.append(f"{hinges} support reliable door performance")

    if _canonical_shelves_included(fields) == "Yes":
        bullets.append("Shelving is included for added everyday storage")

    seen: set[str] = set()
    unique: list[str] = []
    for bullet in bullets:
        normalized = _norm(bullet)
        if normalized and normalized not in seen:
            seen.add(normalized)
            unique.append(bullet)
    return unique


def _norm(value: Any) -> str:
    return " ".join(str(value or "").strip().lower().replace("&", " and ").replace("-", " ").split())


def _clean(value: Any) -> Optional[str]:
    text = str(value or "").strip()
    return text or None
