"""Canonical collection landing field schema for channel presentation push."""

from __future__ import annotations

import json
from typing import Any, Dict, List, Optional

SHOPIFY_NAMESPACE = "custom"
MAGENTO_ATTRIBUTE_PREFIX = "hs_"
COLLECTION_LANDING_ASSET_FIELD_KEYS = {
    "thumbnail_image_url",
    "category_icon_url",
    "pdf_url",
    "hero_images",
}

EMPTY_BADGES_PAYLOAD: Dict[str, Any] = {
    "badges": [],
    "availability_locations": [],
}


COLLECTION_LANDING_FIELDS: List[Dict[str, str]] = [
    {"key": "page_type", "shopify_type": "single_line_text_field", "magento_input": "text"},
    {"key": "brand", "shopify_type": "single_line_text_field", "magento_input": "text"},
    {"key": "subtitle", "shopify_type": "single_line_text_field", "magento_input": "text"},
    {"key": "short_description", "shopify_type": "multi_line_text_field", "magento_input": "textarea"},
    {"key": "thumbnail_image_url", "shopify_type": "url", "magento_input": "text"},
    {"key": "category_icon_url", "shopify_type": "url", "magento_input": "text"},
    {"key": "pdf_url", "shopify_type": "url", "magento_input": "text"},
    {"key": "starting_price", "shopify_type": "number_decimal", "magento_input": "text"},
    {"key": "compare_at_price", "shopify_type": "number_decimal", "magento_input": "text"},
    {"key": "hero_images", "shopify_type": "json", "magento_input": "textarea"},
    {"key": "badges", "shopify_type": "json", "magento_input": "textarea"},
    {"key": "feature_bullets", "shopify_type": "json", "magento_input": "textarea"},
    {"key": "cta_rows", "shopify_type": "json", "magento_input": "textarea"},
    {"key": "sample_product", "shopify_type": "json", "magento_input": "textarea"},
    {"key": "availability_filters", "shopify_type": "json", "magento_input": "textarea"},
    {"key": "landing_metadata", "shopify_type": "json", "magento_input": "textarea"},
    {"key": "matching_collection_slugs", "shopify_type": "json", "magento_input": "textarea"},
    {"key": "sku_prefixes", "shopify_type": "json", "magento_input": "textarea"},
    {"key": "description_html", "shopify_type": "multi_line_text_field", "magento_input": "textarea"},
    {"key": "specifications_html", "shopify_type": "multi_line_text_field", "magento_input": "textarea"},
    {"key": "materials_html", "shopify_type": "multi_line_text_field", "magento_input": "textarea"},
    {"key": "assembly_html", "shopify_type": "multi_line_text_field", "magento_input": "textarea"},
    {"key": "is_collection", "shopify_type": "boolean", "magento_input": "boolean"},
    {"key": "has_collections", "shopify_type": "boolean", "magento_input": "boolean"},
    {"key": "taxonomy_path_slug", "shopify_type": "single_line_text_field", "magento_input": "text"},
    {"key": "parent_path_slug", "shopify_type": "single_line_text_field", "magento_input": "text"},
    {"key": "parent_remote_id", "shopify_type": "single_line_text_field", "magento_input": "text"},
    {"key": "child_remote_ids", "shopify_type": "json", "magento_input": "textarea"},
    {"key": "sibling_remote_ids", "shopify_type": "json", "magento_input": "textarea"},
    {"key": "child_taxonomy_nodes", "shopify_type": "json", "magento_input": "textarea"},
    {"key": "sibling_taxonomy_nodes", "shopify_type": "json", "magento_input": "textarea"},
    {"key": "start_shopping_config", "shopify_type": "json", "magento_input": "textarea"},
    {"key": "shopping_intersections", "shopify_type": "json", "magento_input": "textarea"},
]

RELATIONSHIP_FIELD_KEYS = {
    "is_collection",
    "has_collections",
    "taxonomy_path_slug",
    "parent_path_slug",
    "parent_remote_id",
    "child_remote_ids",
    "sibling_remote_ids",
    "child_taxonomy_nodes",
    "sibling_taxonomy_nodes",
    "start_shopping_config",
    "shopping_intersections",
}

COLLECTION_LANDING_NON_ASSET_FIELD_KEYS = {
    field["key"] for field in COLLECTION_LANDING_FIELDS if field["key"] not in COLLECTION_LANDING_ASSET_FIELD_KEYS
}


def magento_attribute_code(key: str) -> str:
    return f"{MAGENTO_ATTRIBUTE_PREFIX}{key}"


def shopify_metafield_key(key: str) -> str:
    return key


def field_label(key: str) -> str:
    return key.replace("_", " ").title()


def normalize_collection_badges(value: Any) -> Optional[Dict[str, Any]]:
    """Normalize badges to Magento/storefront JSON shape.

    Accepted inputs:
    - ``["Grab & Go", ...]`` (legacy one-per-line / list)
    - ``{"items": [...]}`` (legacy DB wrapper)
    - ``{"badges": [...], "availability_locations": [...]}`` (canonical)
    - JSON string of any of the above

    Returns ``None`` when empty.
    """
    if value is None or value == "" or value == [] or value == {}:
        return None

    parsed: Any = value
    if isinstance(value, str):
        text = value.strip()
        if not text:
            return None
        if text.startswith("{") or text.startswith("["):
            try:
                parsed = json.loads(text)
            except json.JSONDecodeError:
                badges = [line.strip() for line in text.splitlines() if line.strip()]
                return {"badges": badges, "availability_locations": []} if badges else None
        else:
            badges = [line.strip() for line in text.splitlines() if line.strip()]
            return {"badges": badges, "availability_locations": []} if badges else None

    badges: List[str] = []
    availability_locations: List[Dict[str, Any]] = []

    if isinstance(parsed, list):
        if all(isinstance(item, str) for item in parsed):
            badges = [str(item).strip() for item in parsed if str(item).strip()]
        elif all(isinstance(item, dict) for item in parsed):
            availability_locations = [_normalize_availability_location(item) for item in parsed]
            availability_locations = [item for item in availability_locations if item]
            for item in availability_locations:
                label = str(item.get("badge") or "").strip()
                if label and label not in badges:
                    badges.append(label)
        else:
            badges = [str(item).strip() for item in parsed if str(item).strip()]
    elif isinstance(parsed, dict):
        if "items" in parsed and "badges" not in parsed and "availability_locations" not in parsed:
            items = parsed.get("items") if isinstance(parsed.get("items"), list) else []
            badges = [str(item).strip() for item in items if str(item).strip()]
        else:
            raw_badges = parsed.get("badges")
            if isinstance(raw_badges, list):
                badges = [str(item).strip() for item in raw_badges if str(item).strip()]
            elif isinstance(raw_badges, str) and raw_badges.strip():
                badges = [raw_badges.strip()]

            raw_locations = parsed.get("availability_locations")
            if isinstance(raw_locations, list):
                availability_locations = [
                    item
                    for item in (_normalize_availability_location(raw) for raw in raw_locations)
                    if item
                ]

            if not badges and availability_locations:
                for item in availability_locations:
                    label = str(item.get("badge") or "").strip()
                    if label and label not in badges:
                        badges.append(label)
    else:
        return None

    if not badges and not availability_locations:
        return None
    return {"badges": badges, "availability_locations": availability_locations}


def _normalize_availability_location(raw: Any) -> Optional[Dict[str, Any]]:
    if not isinstance(raw, dict):
        return None
    badge = str(raw.get("badge") or "").strip()
    meaning = str(raw.get("meaning") or "").strip()
    locations_raw = raw.get("locations")
    locations: Any
    if isinstance(locations_raw, list):
        locations = [str(item).strip() for item in locations_raw if str(item).strip()]
    elif isinstance(locations_raw, str) and locations_raw.strip():
        locations = locations_raw.strip()
    else:
        locations = []
    if not badge and not meaning and not locations:
        return None
    out: Dict[str, Any] = {"badge": badge, "locations": locations}
    if meaning:
        out["meaning"] = meaning
    return out


def serialize_field_value(key: str, value: Any) -> Optional[str]:
    if value is None:
        return None
    if key == "badges":
        value = normalize_collection_badges(value)
        if value is None:
            return None
    if isinstance(value, bool):
        return "true" if value else "false"
    if isinstance(value, (list, dict)):
        if not value:
            return None
        if (
            key == "badges"
            and isinstance(value, dict)
            and not value.get("badges")
            and not value.get("availability_locations")
        ):
            return None
        return json.dumps(value, ensure_ascii=False)
    text = str(value).strip()
    return text or None


def build_channel_field_payload(
    collection: Dict[str, Any],
    *,
    field_keys: Optional[set[str]] = None,
) -> Dict[str, Optional[str]]:
    """Normalize collection landing row → canonical string values per field key."""
    out: Dict[str, Optional[str]] = {}
    list_fields = {
        "hero_images",
        "feature_bullets",
        "cta_rows",
        "sample_product",
        "availability_filters",
        "matching_collection_slugs",
        "sku_prefixes",
        "start_shopping_config",
    }
    for field in COLLECTION_LANDING_FIELDS:
        key = field["key"]
        if field_keys is not None and key not in field_keys:
            continue
        raw = collection.get(key)
        if key == "badges":
            out[key] = serialize_field_value(key, raw)
        elif key in list_fields and isinstance(raw, list):
            out[key] = serialize_field_value(key, raw)
        elif key == "starting_price":
            price = collection.get("starting_price")
            if price is None:
                price = collection.get("computed_starting_price")
            out[key] = serialize_field_value(key, price)
        elif key == "compare_at_price":
            out[key] = serialize_field_value(key, collection.get("compare_at_price"))
        else:
            out[key] = serialize_field_value(key, raw)
    if "page_type" in out and not out.get("page_type"):
        out["page_type"] = "collection"
    return out
