from typing import Dict, Any, List, Optional
from decimal import Decimal

# Константа для "бесконечного" наличия в Recommerce
# Используется вместо "inf", который API не принимает
RECOMMERCE_INFINITY_COUNT = 999999


def to_api_product(
    product: Any,
    stock_count: Optional[int] = None,
    fields: Optional[List[str]] = None,
    for_create: bool = False
) -> Dict[str, Any]:
    """
    Преобразование внутреннего товара в формат Recommerce API.

    Recommerce API использует form-data для POST запросов, поэтому вложенные поля
    представляются в плоском формате: price[amount], price[currency]

    Args:
        product: Экземпляр модели Product
        stock_count: Остаток товара (вычисляется отдельно, т.к. зависит от склада)
        fields: Список полей для экспорта. Если None - экспортируются все базовые поля.
                Поддерживаемые поля: 'sku', 'name', 'price', 'description', 'count', 'images'.
        for_create: Если True - включает все обязательные поля для создания товара.

    Returns:
        Dict: Плоский словарь для form-data запроса
    """
    data = {}

    # Если поля не указаны, берем базовый набор (без тяжелых полей типа картинок)
    if fields is None:
        fields = ['sku', 'name', 'price']

    # Для создания товара добавляем все обязательные поля
    if for_create:
        fields = list(set(fields) | {'sku', 'name', 'price', 'parent_category_sku'})

    # SKU (Артикул) - обязательное поле для идентификации
    sku = getattr(product, 'sku', str(product.id))

    if 'sku' in fields:
        data['sku'] = sku

    if 'name' in fields:
        data['name'] = product.name

    if 'parent_category_sku' in fields:
        # Получаем категорию через external_category или fallback на M2M categories
        _, category_sku = product.get_category_for_integration('recommerce')
        if category_sku:
            data['parent_category_sku'] = category_sku

    # Вычисляем has_discount до блока price (нужно для is_special)
    has_discount = product.sale_price and product.price and product.sale_price < product.price

    if 'price' in fields:
        # Recommerce ожидает price[amount] и price[currency] в form-data формате
        # Значения передаём как строки (так работает в проверенном скрипте)

        if has_discount:
            # Есть скидка: текущая цена = sale_price, старая = price
            data['price[amount]'] = str(float(product.sale_price))
            data['price[currency]'] = 'BYN'
            # price_old - как в рабочем скрипте (не old_price из документации)
            data['price_old[amount]'] = str(float(product.price))
            data['price_old[currency]'] = 'BYN'
        else:
            # Нет скидки: только основная цена
            data['price[amount]'] = str(float(product.price or 0))
            data['price[currency]'] = 'BYN'
            # Важно: передаем "0" для price_old, чтобы сбросить зачеркнутую цену (как в рабочем скрипте)
            data['price_old[amount]'] = "0"
            data['price_old[currency]'] = 'BYN'

    if 'content' in fields:
        # content включает название и описание
        data['name'] = product.name
        data['description'] = product.description or ''

    if 'description' in fields:
        data['description'] = product.description or ''

    if 'count' in fields and stock_count is not None:
        data['count'] = stock_count

    if 'images' in fields:
        # Recommerce ожидает images[] для массива картинок
        if hasattr(product, 'photos'):
            for idx, photo in enumerate(product.photos.all()):
                if photo.image:
                    data[f'images[{idx}]'] = photo.image.url

    # Обработка маркетинговых флагов (формат: 1/0 для Recommerce API)
    # Добавляем только если поле указано в fields ИЛИ fields=None (полное обновление)
    if fields is None or 'is_new' in fields:
        if hasattr(product, 'is_new'):
            data['new'] = 1 if product.is_new else 0

    if fields is None or 'is_popular' in fields:
        if hasattr(product, 'is_popular'):
            data['popular'] = 1 if product.is_popular else 0

    # special - из модели is_special ИЛИ автоматически при наличии скидке
    if fields is None or 'is_special' in fields:
        if hasattr(product, 'is_special'):
            data['special'] = 1 if (product.is_special or has_discount) else 0
        else:
            data['special'] = 1 if has_discount else 0

    return data


def from_api_order(data: Dict[str, Any]) -> Dict[str, Any]:
    """
    Преобразование заказа из Recommerce в DTO (словарь) для создания внутреннего заказа.
    
    Args:
        data: JSON заказа от Recommerce
        
    Returns:
        Dict: Структурированные данные для создания Order
    """
    # Извлекаем основные поля
    recommerce_id = data.get('id')
    customer_data = data.get('customer', {})
    delivery_data = data.get('delivery', {})
    items_data = data.get('products', [])
    
    # Формируем DTO
    return {
        'external_id': str(recommerce_id),
        'source': 'recommerce',
        'status_external': data.get('state'),
        'date_created': data.get('date'), # Unix timestamp
        'customer': {
            'name': customer_data.get('name'),
            'phone': customer_data.get('phone'),
            'email': customer_data.get('email'),
            'address': _extract_address(data),
        },
        'items': [
            {
                'sku': item.get('sku'),
                'quantity': item.get('count', 1),
                'price': item.get('price', {}).get('amount', 0),
                'name': item.get('title'),
            }
            for item in items_data
        ],
        'total_amount': data.get('total_amount', {}).get('amount'),
        'notes': data.get('note'),
    }


def _extract_address(data: Dict[str, Any]) -> str:
    """Вспомогательная функция для сборки адреса"""
    delivery = data.get('delivery', {})
    fields = delivery.get('fields', [])
    
    # Recommerce может хранить адрес в полях доставки
    address_parts = []
    
    # Пробуем найти стандартные поля
    for field in fields:
        if field.get('value'):
            address_parts.append(f"{field.get('name')}: {field.get('value')}")
            
    if not address_parts:
        # Fallback если адрес в другом месте или не задан
        return "Адрес не указан в стандартных полях"
        
    return ", ".join(address_parts)