"""
Модель для управления процессом создания таймлапса
Single Responsibility: только данные и состояние процесса таймлапса
"""

from PySide6.QtCore import QObject, Signal, QThread
from datetime import datetime, timedelta
from pathlib import Path
from typing import List, Optional, Callable
from dataclasses import dataclass, field
from enum import Enum


class TimelapseStatus(Enum):
    """Статус процесса создания таймлапса"""
    IDLE = "idle"
    PREPARING = "preparing"
    DOWNLOADING = "downloading"
    PROCESSING = "processing"
    CREATING_VIDEO = "creating_video"
    COMPLETED = "completed"
    FAILED = "failed"
    CANCELLED = "cancelled"


@dataclass
class TimelapseConfig:
    """Конфигурация таймлапса"""
    source_id: int
    start_date: datetime
    end_date: datetime
    output_path: Path
    fps: int = 10
    quality: int = 90  # качество видео (0-100)
    include_metadata: bool = True
    output_format: str = "mp4"  # mp4, gif, webm


@dataclass
class TimelapseProgress:
    """Прогресс создания таймлапса"""
    status: TimelapseStatus
    current: int = 0
    total: int = 0
    message: str = ""
    current_date: Optional[datetime] = None
    downloaded_files: List[Path] = field(default_factory=list)


class TimelapseModel(QObject):
    """
    Модель для управления созданием таймлапса
    Хранит состояние и предоставляет интерфейс для контроллера
    """

    # Сигналы для оповещения о изменениях
    progress_updated = Signal(TimelapseProgress)
    status_changed = Signal(TimelapseStatus)
    log_message = Signal(str)

    def __init__(self):
        super().__init__()
        self._current_progress = TimelapseProgress(status=TimelapseStatus.IDLE)
        self._config: Optional[TimelapseConfig] = None
        self._is_cancelled = False

    def configure(self, config: TimelapseConfig) -> bool:
        """
        Настраивает таймлапс

        Args:
            config: Конфигурация таймлапса

        Returns:
            True если конфигурация валидна
        """
        # Валидация параметров
        if config.start_date >= config.end_date:
            self.log_message.emit("Ошибка: Дата начала должна быть раньше даты окончания")
            return False

        if config.fps < 1 or config.fps > 60:
            self.log_message.emit("Ошибка: FPS должен быть в диапазоне 1-60")
            return False

        if not config.output_path.parent.exists():
            self.log_message.emit(f"Ошибка: Папка {config.output_path.parent} не существует")
            return False

        self._config = config
        self._is_cancelled = False

        # Рассчитываем общее количество кадров
        delta = config.end_date - config.start_date
        total_frames = delta.days + 1
        self._current_progress = TimelapseProgress(
            status=TimelapseStatus.PREPARING,
            total=total_frames,
            message=f"Подготовка к созданию таймлапса из {total_frames} кадров"
        )

        self.log_message.emit(f"Настроен таймлапс: {total_frames} кадров, {config.fps} FPS")
        return True

    def get_total_frames(self) -> int:
        """Возвращает общее количество кадров"""
        if self._config:
            delta = self._config.end_date - self._config.start_date
            return delta.days + 1
        return 0

    def update_progress(self, current_frame: int, total_frames: int,
                        message: str = "", current_date: datetime = None):
        """
        Обновляет прогресс создания таймлапса

        Args:
            current_frame: Текущий кадр
            total_frames: Всего кадров
            message: Сообщение о прогрессе
            current_date: Текущая обрабатываемая дата
        """
        self._current_progress.current = current_frame
        self._current_progress.total = total_frames
        self._current_progress.message = message or self._current_progress.message
        self._current_progress.current_date = current_date or self._current_progress.current_date

        # Вычисляем процент
        if total_frames > 0:
            percent = (current_frame / total_frames) * 100
            status_text = f"{percent:.1f}%"

        self.progress_updated.emit(self._current_progress)

    def set_status(self, status: TimelapseStatus, message: str = ""):
        """
        Устанавливает статус процесса

        Args:
            status: Новый статус
            message: Сообщение (опционально)
        """
        self._current_progress.status = status
        if message:
            self._current_progress.message = message
        self.status_changed.emit(status)
        self.progress_updated.emit(self._current_progress)
        self.log_message.emit(message or f"Статус: {status.value}")

    def add_downloaded_file(self, filepath: Path):
        """Добавляет скачанный файл в список"""
        self._current_progress.downloaded_files.append(filepath)

    def get_downloaded_files(self) -> List[Path]:
        """Возвращает список скачанных файлов"""
        return self._current_progress.downloaded_files.copy()

    def cancel(self):
        """Отменяет создание таймлапса"""
        self._is_cancelled = True
        self.set_status(TimelapseStatus.CANCELLED, "Создание таймлапса отменено пользователем")

    def is_cancelled(self) -> bool:
        """Проверяет, отменен ли процесс"""
        return self._is_cancelled

    def get_config(self) -> Optional[TimelapseConfig]:
        """Возвращает конфигурацию таймлапса"""
        return self._config

    def reset(self):
        """Сбрасывает состояние модели"""
        self._config = None
        self._is_cancelled = False
        self._current_progress = TimelapseProgress(status=TimelapseStatus.IDLE)
        self.progress_updated.emit(self._current_progress)

    def generate_date_sequence(self) -> List[datetime]:
        """
        Генерирует последовательность дат для таймлапса

        Returns:
            Список дат для каждого кадра
        """
        if not self._config:
            return []

        dates = []
        current = self._config.start_date.replace(hour=12, minute=0, second=0)

        while current <= self._config.end_date:
            dates.append(current)
            current += timedelta(days=1)

        return dates

    def get_estimated_size(self) -> int:
        """
        Оценивает примерный размер видео в байтах

        Returns:
            Оценочный размер или 0 если невозможно оценить
        """
        if not self._config:
            return 0

        # Приблизительная оценка: ~500KB на кадр для HD видео
        total_frames = self.get_total_frames()
        estimated_bytes = total_frames * 500 * 1024

        # Корректируем в зависимости от FPS и качества
        estimated_bytes = estimated_bytes * (self._config.fps / 30) * (self._config.quality / 100)

        return int(estimated_bytes)

    def get_formatted_estimated_size(self) -> str:
        """Возвращает отформатированную оценку размера"""
        size_bytes = self.get_estimated_size()

        if size_bytes < 1024:
            return f"{size_bytes} B"
        elif size_bytes < 1024 * 1024:
            return f"{size_bytes / 1024:.1f} KB"
        elif size_bytes < 1024 * 1024 * 1024:
            return f"{size_bytes / (1024 * 1024):.1f} MB"
        else:
            return f"{size_bytes / (1024 * 1024 * 1024):.2f} GB"