import math
import re
from typing import Dict, Optional

def calculate_shipping_cost(shipment: Dict) -> Optional[Dict]:
    """
    Расчёт стоимости авиаперевозки на основе параметров груза.
    Возвращает словарь с ключами:
        total_usd, total_rub, chargeable_weight, actual_weight, volume_weight
    или None, если не хватает данных.
    """
    try:
        # Проверяем наличие обязательных данных
        if not all(k in shipment for k in ['total_weight_kg', 'dimensions', 'cargo_value']):
            return None
        
        # Параметры груза
        actual_weight = shipment.get('total_weight_kg', 0)
        if not actual_weight or actual_weight <= 0:
            return None
            
        # Расчёт объёмного веса
        dimensions = shipment.get('dimensions', [])
        if not dimensions:
            return None
            
        total_volume_weight = 0
        for dim in dimensions:
            if dim.get('length_cm') and dim.get('width_cm') and dim.get('height_cm'):
                # Объёмный вес = (Д×Ш×В в метрах) × 167
                length_m = dim['length_cm'] / 100
                width_m = dim['width_cm'] / 100
                height_m = dim['height_cm'] / 100
                volume = length_m * width_m * height_m
                volume_weight = volume * 167
                total_volume_weight += volume_weight
        
        # Платный вес (оплачивается по большему)
        chargeable_weight = max(actual_weight, total_volume_weight)
        chargeable_weight = math.ceil(chargeable_weight)  # округляем вверх
        
        # Базовый тариф в зависимости от веса (USD/кг)
        if chargeable_weight < 45:
            base_rate = 6.5
        elif chargeable_weight < 100:
            base_rate = 5.5
        elif chargeable_weight < 300:
            base_rate = 4.5
        elif chargeable_weight < 500:
            base_rate = 3.8
        elif chargeable_weight < 1000:
            base_rate = 3.2
        else:
            base_rate = 2.8
            
        # Топливный сбор и сбор за безопасность
        fuel_surcharge_rate = 0.9  # USD/кг
        min_fuel_surcharge = 90    # USD минимум
        
        # Терминальные сборы
        terminal_export_rate = 0.22  # USD/кг (~20 руб/кг)
        terminal_export_fixed = 25   # USD фиксированных сборов (~2300 руб)
        terminal_import_rate = 0.35  # EUR/кг ≈ 0.38 USD/кг по курсу 1.1
        
        # Таможенное оформление
        customs_export = 170  # USD (~15500 руб)
        customs_import = 220  # EUR ≈ 242 USD
        
        # Надбавки за особые условия
        special_rate_multiplier = 1.0
        
        # Терморежим (+15…+25 °C)
        if shipment.get('special_transport_requirements') and 'термо' in str(shipment.get('special_transport_requirements', '')).lower():
            special_rate_multiplier *= 1.3  # +30%
        
        # Страхование
        cargo_value_usd = 0
        cargo_value_str = shipment.get('cargo_value', '0')
        # Извлекаем числовое значение из строки (например, "18 500 EUR" -> 18500)
        value_match = re.search(r'[\d\s]+', cargo_value_str.replace(' ', ''))
        if value_match:
            cargo_value_usd = float(value_match.group().replace(' ', ''))
            # Если указано в EUR, конвертируем
            if 'EUR' in cargo_value_str or '€' in cargo_value_str:
                cargo_value_usd *= 1.1  # приблизительный курс EUR/USD
        
        insurance_cost = cargo_value_usd * 0.01  # 1% от стоимости груза
        
        # Расчёт компонентов
        base_freight = chargeable_weight * base_rate * special_rate_multiplier
        fuel_surcharge = max(chargeable_weight * fuel_surcharge_rate, min_fuel_surcharge)
        terminal_export = chargeable_weight * terminal_export_rate + terminal_export_fixed
        terminal_import = chargeable_weight * 0.38  # конвертация EUR->USD
        customs_total = customs_export + customs_import
        
        # Дополнительные услуги
        additional_services = shipment.get('additional_services', [])
        additional_cost = 0
        if isinstance(additional_services, list):
            if 'уведомление о прибытии' in str(additional_services).lower():
                additional_cost += 25  # USD
        
        # Итог
        total_usd = (base_freight + fuel_surcharge + terminal_export + 
                     terminal_import + customs_total + additional_cost + insurance_cost)
        
        # Конвертация в рубли для удобства (курс USD/RUB ~90)
        total_rub = total_usd * 90
        
        return {
            "total_usd": round(total_usd, 2),
            "total_rub": round(total_rub, 2),
            "chargeable_weight": chargeable_weight,
            "actual_weight": actual_weight,
            "volume_weight": round(total_volume_weight, 2)
        }
    except Exception as e:
        # Логирование ошибки, если нужно
        return None
