import logging
from .parser import LyngSatParser
from .models import LyngSat
from mainapp.models import Polarization, Standard, Modulation, Satellite
from dbapp.settings.base import FLARESOLVERR_URL

logger = logging.getLogger(__name__)


def fill_lyngsat_data(
    target_sats: list[str],
    regions: list[str] = None,
    task_id: str = None,
    update_progress=None
):
    """
    Заполняет данные Lyngsat для указанных спутников и регионов.
    
    Args:
        target_sats: Список названий спутников для обработки
        regions: Список регионов для парсинга (по умолчанию все)
        task_id: ID задачи Celery для логирования
        update_progress: Функция для обновления прогресса (current, total, status)
    
    Returns:
        dict: Статистика обработки с ключами:
            - total_satellites: общее количество спутников
            - total_sources: общее количество источников
            - created: количество созданных записей
            - updated: количество обновленных записей
            - errors: список ошибок
    """
    log_prefix = f"[Task {task_id}]" if task_id else "[Lyngsat]"
    stats = {
        'total_satellites': 0,
        'total_sources': 0,
        'created': 0,
        'updated': 0,
        'errors': []
    }
    
    if regions is None:
        regions = ["europe", "asia", "america", "atlantic"]
    
    logger.info(f"{log_prefix} Начало парсинга данных")
    logger.info(f"{log_prefix} Спутники: {', '.join(target_sats)}")
    logger.info(f"{log_prefix} Регионы: {', '.join(regions)}")
    
    if update_progress:
        update_progress(0, len(target_sats), "Инициализация парсера...")
    
    try:
        parser = LyngSatParser(
            flaresolver_url=FLARESOLVERR_URL,
            target_sats=target_sats,
            regions=regions
        )
        
        logger.info(f"{log_prefix} Получение данных со спутников...")
        if update_progress:
            update_progress(0, len(target_sats), "Получение данных со спутников...")
        
        lyngsat_data = parser.get_satellites_data()
        stats['total_satellites'] = len(lyngsat_data)
        
        logger.info(f"{log_prefix} Получено данных по {stats['total_satellites']} спутникам")
        
        for idx, (sat_name, data) in enumerate(lyngsat_data.items(), 1):
            logger.info(f"{log_prefix} Обработка спутника {idx}/{stats['total_satellites']}: {sat_name}")
            
            if update_progress:
                update_progress(idx, stats['total_satellites'], f"Обработка {sat_name}...")
            
            url = data['url']
            sources = data['sources']
            stats['total_sources'] += len(sources)
            
            logger.info(f"{log_prefix} Найдено {len(sources)} источников для {sat_name}")
            
            # Находим спутник в базе по имени или альтернативному имени (lowercase)
            from django.db.models import Q
            sat_name_lower = sat_name.lower()
            try:
                sat_obj = Satellite.objects.get(
                    Q(name__icontains=sat_name_lower) | Q(alternative_name__icontains=sat_name_lower)
                )
                logger.debug(f"{log_prefix} Спутник {sat_name} найден в базе (ID: {sat_obj.id})")
            except Satellite.DoesNotExist:
                error_msg = f"Спутник '{sat_name}' не найден в базе данных"
                logger.warning(f"{log_prefix} {error_msg}")
                stats['errors'].append(error_msg)
                continue
            except Satellite.MultipleObjectsReturned:
                error_msg = f"Найдено несколько спутников с именем '{sat_name}'"
                logger.warning(f"{log_prefix} {error_msg}")
                stats['errors'].append(error_msg)
                continue
            
            for source_idx, source in enumerate(sources, 1):
                try:
                    # Парсим частоту
                    try:
                        freq = float(source['freq'])
                    except (ValueError, TypeError):
                        freq = -1.0
                        error_msg = f"Некорректная частота для {sat_name}: {source.get('freq')}"
                        logger.debug(f"{log_prefix} {error_msg}")
                        stats['errors'].append(error_msg)
                    
                    last_update = source['last_update']
                    fec = source['metadata'].get('fec')
                    modulation_name = source['metadata'].get('modulation')
                    standard_name = source['metadata'].get('standard')
                    symbol_velocity = source['metadata'].get('symbol_rate')
                    polarization_name = source['pol']
                    channel_info = source['provider_name']

                    # Создаем или получаем связанные объекты
                    pol_obj, _ = Polarization.objects.get_or_create(
                        name=polarization_name if polarization_name else "-"
                    )

                    mod_obj, _ = Modulation.objects.get_or_create(
                        name=modulation_name if modulation_name else "-"
                    )

                    standard_obj, _ = Standard.objects.get_or_create(
                        name=standard_name if standard_name else "-"
                    )

                    # Создаем или обновляем запись Lyngsat
                    lyng_obj, created = LyngSat.objects.update_or_create(
                        id_satellite=sat_obj,
                        frequency=freq,
                        polarization=pol_obj,
                        defaults={
                            "modulation": mod_obj,
                            "standard": standard_obj,
                            "sym_velocity": symbol_velocity if symbol_velocity else 0,
                            "channel_info": channel_info[:20] if channel_info else "",
                            "last_update": last_update,
                            "fec": fec[:30] if fec else "",
                            "url": url
                        }
                    )
                    
                    if created:
                        stats['created'] += 1
                        logger.debug(f"{log_prefix} Создана запись для {sat_name} {freq} МГц")
                    else:
                        stats['updated'] += 1
                        logger.debug(f"{log_prefix} Обновлена запись для {sat_name} {freq} МГц")
                    
                    # Логируем прогресс каждые 10 источников
                    if source_idx % 10 == 0:
                        logger.info(f"{log_prefix} Обработано {source_idx}/{len(sources)} источников для {sat_name}")
                        
                except Exception as e:
                    error_msg = f"Ошибка при обработке источника {sat_name}: {str(e)}"
                    logger.error(f"{log_prefix} {error_msg}", exc_info=True)
                    stats['errors'].append(error_msg)
                    continue
            
            logger.info(f"{log_prefix} Завершена обработка {sat_name}: создано {stats['created']}, обновлено {stats['updated']}")
                    
    except Exception as e:
        error_msg = f"Критическая ошибка: {str(e)}"
        logger.error(f"{log_prefix} {error_msg}", exc_info=True)
        stats['errors'].append(error_msg)
    
    logger.info(f"{log_prefix} Обработка завершена. Итого: создано {stats['created']}, обновлено {stats['updated']}, ошибок {len(stats['errors'])}")
    
    if update_progress:
        update_progress(stats['total_satellites'], stats['total_satellites'], "Завершено")
    
    return stats


def link_lyngsat_to_sources():
    pass