"""Extracts normalized SKU information from a raw AliExpress SKU DTO."""
from __future__ import annotations

from dataclasses import dataclass, field
from typing import Any, Optional

from ....utils.helpers import as_list, first_present, round2, to_float, to_int


@dataclass
class SkuInfo:
    """Normalized view of a single AliExpress SKU."""

    sku_id: str
    color: Optional[str] = None
    size: Optional[str] = None
    supplier_price: float = 0.0
    sale_price: float = 0.0
    stock: int = 0
    images: list[str] = field(default_factory=list)

    def to_dict(self) -> dict:
        return {
            "skuId": self.sku_id,
            "color": self.color,
            "size": self.size,
            "supplierPrice": round2(self.supplier_price),
            "salePrice": round2(self.sale_price),
            "stock": self.stock,
            "images": self.images,
        }


class SkuAnalyzer:
    """Single responsibility: turn a raw SKU DTO into a clean ``SkuInfo``."""

    COLOR_PROPERTY_NAMES = ("color", "colour", "颜色")
    SIZE_PROPERTY_NAMES = ("size", "尺寸", "shoe size", "length")

    def analyze(self, sku_dto: dict) -> SkuInfo:
        sku_id = str(
            first_present(sku_dto, ("sku_id", "skuId", "id", "sku_attr"), default="")
        )
        color, size, images = self._extract_properties(sku_dto)

        # "offer_sale_price" is the discounted price buyers actually pay; it is
        # the real supplier cost for a dropshipper. Fall back to the list price.
        supplier_price = to_float(
            first_present(
                sku_dto,
                ("offer_sale_price", "offer_bulk_sale_price", "sku_price", "price"),
            )
        )
        sale_price = to_float(
            first_present(sku_dto, ("sku_price", "sale_price", "price"),
                          default=supplier_price)
        )
        stock = to_int(
            first_present(
                sku_dto,
                ("sku_available_stock", "available_stock", "ipm_sku_stock", "stock",
                 "sku_stock"),
            )
        )

        sku_image = first_present(sku_dto, ("sku_image", "image", "sku_img"))
        if sku_image and sku_image not in images:
            images.append(str(sku_image))

        return SkuInfo(
            sku_id=sku_id,
            color=color,
            size=size,
            supplier_price=supplier_price,
            sale_price=sale_price,
            stock=stock,
            images=images,
        )

    # ------------------------------------------------------------------ #
    def _extract_properties(
        self, sku_dto: dict
    ) -> tuple[Optional[str], Optional[str], list[str]]:
        """Pull color / size / images out of the SKU property list."""
        color: Optional[str] = None
        size: Optional[str] = None
        images: list[str] = []

        properties = as_list(
            first_present(sku_dto, ("ae_sku_property_dtos", "sku_properties",
                                    "properties"))
        )
        for prop in properties:
            if not isinstance(prop, dict):
                continue
            name = str(
                first_present(prop, ("sku_property_name", "property_name", "name"),
                              default="")
            ).strip().lower()
            value = first_present(
                prop,
                ("property_value_definition_name", "sku_property_value",
                 "property_value", "value"),
            )
            image = first_present(prop, ("sku_image", "image"))
            if image:
                images.append(str(image))
            if value is None:
                continue
            # Substring match: real names include variations such as
            # "Kid Size", "Shoe Size", "Colour".
            if color is None and any(k in name for k in self.COLOR_PROPERTY_NAMES):
                color = str(value)
            elif size is None and any(k in name for k in self.SIZE_PROPERTY_NAMES):
                size = str(value)
        return color, size, images
