"""
Video Processing Components - Компоненты обработки видео
"""

import sys
from pathlib import Path
from typing import Dict, Any, Optional
from ..core import FrameworkComponent, ProcessingContext

# Импорт существующих модулей
project_root = Path(__file__).parent.parent.parent
src_path = project_root / "src"
sys.path.insert(0, str(src_path))

try:
    from core.video_processor import VideoProcessor
    from core.audio_processor import AudioProcessor
    VIDEO_PROCESSOR_AVAILABLE = True
except ImportError as e:
    print(f"Warning: VideoProcessor not available: {e}")
    VIDEO_PROCESSOR_AVAILABLE = False

class VideoExtractionComponent(FrameworkComponent):
    """Компонент извлечения аудио из видео"""

    def __init__(self, name: str = "video_extraction", config: Dict[str, Any] = None):
        super().__init__(name, config)
        self.video_processor = None
        self.audio_processor = None

    def initialize(self) -> bool:
        """Инициализация компонента"""
        if not super().initialize():
            self.logger.error("Base component initialization failed")
            return False

        if not VIDEO_PROCESSOR_AVAILABLE:
            self.logger.error("VideoProcessor module not available")
            return False

        try:
            self.logger.info("Initializing VideoProcessor...")
            self.video_processor = VideoProcessor()
            self.logger.info("VideoProcessor initialized successfully")

            self.logger.info("Initializing AudioProcessor...")
            self.audio_processor = AudioProcessor()
            self.logger.info("AudioProcessor initialized successfully")

            self.logger.info("Initialized video and audio processors")
            return True
        except Exception as e:
            self.logger.error(f"Failed to initialize processors: {e}")
            import traceback
            self.logger.error(f"Traceback: {traceback.format_exc()}")
            return False

    def process(self, context: ProcessingContext) -> ProcessingContext:
        """Обработка: извлечение аудио из видео"""
        if not self.video_processor or not self.audio_processor:
            raise RuntimeError("Processors not initialized")

        input_file = context.input_file
        if not input_file.exists():
            raise FileNotFoundError(f"Input video file not found: {input_file}")

        self.logger.info(f"Extracting audio from: {input_file}")

        try:
            # Колбэк для обновления прогресса
            if context.progress_callback:
                context.progress_callback("Video Extraction: Starting", 10)

            # Извлекаем аудио (метод возвращает путь к аудио файлу и метаданные)
            audio_path, video_info = self.video_processor.extract_audio(str(input_file))

            if context.progress_callback:
                context.progress_callback("Video Extraction: Processing", 50)

            if not audio_path:
                raise RuntimeError("Audio extraction failed - no audio file returned")

            audio_file = Path(audio_path)
            if not audio_file.exists():
                raise RuntimeError(f"Audio extraction failed - file not found: {audio_file}")

            # Сохраняем путь к аудио в контексте
            context.audio_file = audio_file

            # Сохраняем метаданные видео
            context.metadata['video_info'] = video_info

            if context.progress_callback:
                context.progress_callback("Video Extraction: Completed", 100)

            self.logger.info(f"Audio extracted successfully: {audio_file}")

        except Exception as e:
            self.logger.error(f"Video extraction failed: {e}")
            raise

        return context

class VideoAssemblyComponent(FrameworkComponent):
    """Компонент сборки финального видео"""

    def __init__(self, name: str = "video_assembly", config: Dict[str, Any] = None):
        super().__init__(name, config)
        self.video_processor = None

    def initialize(self) -> bool:
        """Инициализация компонента"""
        if not super().initialize():
            return False

        if not VIDEO_PROCESSOR_AVAILABLE:
            self.logger.error("VideoProcessor module not available")
            return False

        try:
            self.video_processor = VideoProcessor()
            self.logger.info("Initialized video processor for assembly")
            return True
        except Exception as e:
            self.logger.error(f"Failed to initialize video processor: {e}")
            return False

    def process(self, context: ProcessingContext) -> ProcessingContext:
        """Обработка: сборка финального видео с переведенным аудио"""
        if not self.video_processor:
            raise RuntimeError("Video processor not initialized")

        # Проверяем наличие необходимых файлов
        if not context.input_file.exists():
            raise FileNotFoundError(f"Original video not found: {context.input_file}")

        # Путь к синтезированному аудио должен быть в метаданных
        synthesized_audio = context.metadata.get('synthesized_audio_file')
        if not synthesized_audio or not Path(synthesized_audio).exists():
            raise FileNotFoundError("Synthesized audio file not found")

        self.logger.info(f"Assembling final video: {context.output_file}")

        try:
            # Колбэк для обновления прогресса
            def progress_callback(stage, progress):
                if context.progress_callback:
                    context.progress_callback(f"Video Assembly: {stage}", progress)

            # Настройки из конфигурации
            settings = context.settings
            preserve_original = settings.get('preserve_original_video', True)
            generate_subtitles = settings.get('generate_subtitles', True)

            # Используем оригинальный video_translator.py напрямую - единственный рабочий способ
            self.logger.info("Using original video_translator.py for reliable processing")
            self._use_original_video_translator(context, progress_callback)

            # Создаем субтитры если нужно
            if generate_subtitles and context.translation:
                subtitle_file = context.output_file.with_suffix('.srt')
                self._create_subtitles(context, subtitle_file)
                context.metadata['subtitle_file'] = str(subtitle_file)

                # Проверяем что субтитры созданы
                if subtitle_file.exists():
                    self.logger.info(f"External subtitles created: {subtitle_file}")

                    # Встраиваем субтитры в видео (опционально)
                    embed_subtitles = self.config.get('embed_subtitles', False)
                    if embed_subtitles:
                        try:
                            self._embed_subtitles(str(context.output_file), str(subtitle_file), progress_callback)
                            self.logger.info(f"Subtitles embedded in video: {subtitle_file}")
                        except Exception as e:
                            self.logger.warning(f"Failed to embed subtitles: {e}, external SRT file available")
                    else:
                        self.logger.info("Subtitle embedding disabled, using external SRT file")
                else:
                    self.logger.warning("Subtitle file was not created")

            if not context.output_file.exists():
                raise RuntimeError("Video assembly failed")

            self.logger.info(f"Video assembled successfully: {context.output_file}")

        except Exception as e:
            self.logger.error(f"Video assembly failed: {e}")
            raise

        return context

    def _create_subtitles(self, context: ProcessingContext, subtitle_file: Path):
        """Создание файла субтитров"""
        try:
            timestamps = context.timestamps or []
            translation = context.translation or ""

            # Простое создание SRT файла
            srt_content = ""
            if timestamps:
                for i, timestamp in enumerate(timestamps):
                    start_time = self._format_time(timestamp.get('start', 0))
                    end_time = self._format_time(timestamp.get('end', 0))
                    text = timestamp.get('translated_text', translation)

                    srt_content += f"{i + 1}\n"
                    srt_content += f"{start_time} --> {end_time}\n"
                    srt_content += f"{text}\n\n"
            else:
                # Если нет временных меток, создаем один блок
                srt_content = f"1\n00:00:00,000 --> 99:99:99,999\n{translation}\n\n"

            with open(subtitle_file, 'w', encoding='utf-8') as f:
                f.write(srt_content)

            self.logger.info(f"Subtitles created: {subtitle_file}")

        except Exception as e:
            self.logger.warning(f"Failed to create subtitles: {e}")

    def _combine_video_audio_simple(self, video_path: str, audio_path: str,
                                   output_path: str, preserve_original: bool = False,
                                   progress_callback=None):
        """Простое объединение видео и аудио через FFmpeg"""
        import subprocess
        import os

        if progress_callback:
            progress_callback("Video Assembly: Combining audio", 50)

        # Проверяем существование файлов
        if not Path(video_path).exists():
            raise FileNotFoundError(f"Video file not found: {video_path}")
        if not Path(audio_path).exists():
            raise FileNotFoundError(f"Audio file not found: {audio_path}")

        # Логируем информацию о файлах
        video_size = os.path.getsize(video_path) / (1024*1024)  # MB
        audio_size = os.path.getsize(audio_path) / (1024*1024)  # MB
        self.logger.info(f"Input video: {video_path} ({video_size:.1f} MB)")
        self.logger.info(f"Input audio: {audio_path} ({audio_size:.1f} MB)")
        self.logger.info(f"Output video: {output_path}")
        self.logger.info(f"Preserve original audio: {preserve_original}")

        # Команда FFmpeg для объединения
        if preserve_original:
            # Смешиваем оригинальное и новое аудио
            cmd = [
                'ffmpeg', '-y',
                '-i', video_path,
                '-i', audio_path,
                '-filter_complex', '[0:a][1:a]amix=inputs=2:duration=longest[a]',
                '-map', '0:v',
                '-map', '[a]',
                '-c:v', 'copy',
                '-c:a', 'aac',
                '-shortest',
                output_path
            ]
        else:
            # Заменяем аудио
            cmd = [
                'ffmpeg', '-y',
                '-i', video_path,
                '-i', audio_path,
                '-map', '0:v',
                '-map', '1:a',
                '-c:v', 'copy',
                '-c:a', 'aac',
                '-shortest',
                output_path
            ]

        if progress_callback:
            progress_callback("Video Assembly: Running FFmpeg", 75)

        self.logger.info(f"Running FFmpeg command: {' '.join(cmd)}")

        # Выполняем команду
        result = subprocess.run(cmd, capture_output=True, text=True)

        # Логируем результат
        self.logger.info(f"FFmpeg return code: {result.returncode}")
        if result.stdout:
            self.logger.info(f"FFmpeg stdout: {result.stdout}")
        if result.stderr:
            self.logger.info(f"FFmpeg stderr: {result.stderr}")

        if result.returncode != 0:
            raise RuntimeError(f"FFmpeg failed: {result.stderr}")

        # Проверяем результат
        if Path(output_path).exists():
            output_size = os.path.getsize(output_path) / (1024*1024)  # MB
            self.logger.info(f"Output file created: {output_path} ({output_size:.1f} MB)")
        else:
            raise RuntimeError(f"Output file was not created: {output_path}")

        if progress_callback:
            progress_callback("Video Assembly: Completed", 100)

        self.logger.info(f"Video assembly completed successfully: {output_path}")

    def _use_original_video_translator(self, context, progress_callback=None):
        """Использует оригинальный video_translator.py для надежной обработки"""
        try:
            # Импортируем оригинальный модуль
            import sys
            from pathlib import Path

            # Импортируем оригинальный video_translator из src/
            project_root = Path(__file__).parent.parent.parent
            sys.path.insert(0, str(project_root / "src"))

            from video_translator import translate_video

            if progress_callback:
                progress_callback("Video Assembly: Using original system", 25)

            # Подготавливаем параметры
            input_video = str(context.input_file)
            output_video = str(context.output_file)
            source_lang = context.source_language if context.source_language != 'auto' else 'en'
            target_lang = context.target_language

            self.logger.info(f"Calling original translate_video:")
            self.logger.info(f"  Input: {input_video}")
            self.logger.info(f"  Output: {output_video}")
            self.logger.info(f"  Languages: {source_lang} -> {target_lang}")

            if progress_callback:
                progress_callback("Video Assembly: Processing with original system", 50)

            # Вызываем оригинальную функцию
            result = translate_video(
                input_video=input_video,
                output_video=output_video,
                source_language=source_lang,
                target_language=target_lang,
                custom_output_dir=str(context.output_file.parent),
                use_gpu=True,
                preserve_original_audio=context.settings.get('preserve_original_video', False)
            )

            if progress_callback:
                progress_callback("Video Assembly: Completed", 100)

            if result:
                self.logger.info("✅ Original video_translator completed successfully")
            else:
                raise RuntimeError("Original video_translator failed")

        except Exception as e:
            self.logger.error(f"Original video_translator failed: {e}")
            raise

    def _embed_subtitles(self, video_path: str, subtitle_path: str, progress_callback=None):
        """Встраивание субтитров в видео"""
        import subprocess
        import os

        if progress_callback:
            progress_callback("Video Assembly: Embedding subtitles", 90)

        # Преобразуем в абсолютные пути
        video_path = os.path.abspath(video_path)
        subtitle_path = os.path.abspath(subtitle_path)

        # Проверяем существование файлов
        if not os.path.exists(video_path):
            raise FileNotFoundError(f"Video file not found: {video_path}")
        if not os.path.exists(subtitle_path):
            raise FileNotFoundError(f"Subtitle file not found: {subtitle_path}")

        # Создаем временный файл для видео с субтитрами
        temp_output = str(Path(video_path).with_suffix('.temp.mp4'))

        # Экранируем путь к субтитрам для Windows/Mac совместимости
        escaped_subtitle_path = subtitle_path.replace('\\', '\\\\').replace(':', '\\:')

        # Команда FFmpeg для встраивания субтитров
        cmd = [
            'ffmpeg', '-y',
            '-i', video_path,
            '-vf', f"subtitles='{escaped_subtitle_path}'",
            '-c:a', 'copy',
            '-c:v', 'libx264',  # Перекодируем видео для совместимости
            temp_output
        ]

        self.logger.info(f"Embedding subtitles with FFmpeg: {' '.join(cmd)}")

        # Выполняем команду
        result = subprocess.run(cmd, capture_output=True, text=True)

        if result.returncode != 0:
            self.logger.error(f"FFmpeg stderr: {result.stderr}")
            raise RuntimeError(f"FFmpeg subtitle embedding failed: {result.stderr}")

        # Заменяем оригинальный файл
        import shutil
        shutil.move(temp_output, video_path)

        self.logger.info(f"Subtitles embedded successfully in: {video_path}")

    def _format_time(self, seconds: float) -> str:
        """Форматирование времени для SRT"""
        hours = int(seconds // 3600)
        minutes = int((seconds % 3600) // 60)
        secs = int(seconds % 60)
        millisecs = int((seconds % 1) * 1000)
        return f"{hours:02d}:{minutes:02d}:{secs:02d},{millisecs:03d}"