# Third party imports
import os
from pathlib import Path
import time
import ffmpeg
import json
import tomlkit
import hashlib
import numpy as np
from moviepy.editor import VideoFileClip, concatenate_videoclips
import subprocess
from pydub import AudioSegment
from pydub.silence import detect_nonsilent

# Local imports
from utils.console import print_step, print_substep

class VideoCompiler:
def load_processed_videos(self):
    """Load list of already processed videos"""
    try:
        if os.path.exists(self.processed_videos_file):
            with open(self.processed_videos_file, 'r') as f:
                return json.load(f)
        return []
    except Exception as e:
        print_substep(f"Error loading processed videos: {str(e)}")
        return []

def save_processed_videos(self):
    """Save list of processed videos"""
    try:
        with open(self.processed_videos_file, 'w') as f:
            json.dump(self.processed_videos, f)
    except Exception as e:
        print_substep(f"Error saving processed videos: {str(e)}")    
    def __init__(self):
        self.config = self.load_config()
        self.config_hash = self.get_config_hash()
        self.results_folder = self.config['paths']['source_folder']
        self.merge_folder = self.config['paths']['merge_folder']
        self.target_duration = self.config['merger']['target_duration'] * 60  # convert to seconds
        self.subreddit_durations = {}
        self.processed_videos_file = "processed_videos.json"
        
        os.makedirs(self.merge_folder, exist_ok=True)
        print_step(f"Looking for videos in: {self.results_folder}")
        print_step(f"Current mode: {self.config['merger']['mode']}")
        print_step(f"Current status: {self.config['merger']['status']}")
        
        self.processed_videos = self.load_processed_videos()

    def get_config_hash(self):
        """Get hash of current config file to detect changes"""
        try:
            with open("merger_config.toml", "rb") as f:
                return hashlib.md5(f.read()).hexdigest()
        except FileNotFoundError:
            return None

    def check_config_changed(self):
        """Check if config file has been modified"""
        current_hash = self.get_config_hash()
        if current_hash != self.config_hash:
            print_step("Config file changed! Reloading settings...")
            self.config = self.load_config()
            self.config_hash = current_hash
            self.results_folder = self.config['paths']['source_folder']
            self.merge_folder = self.config['paths']['merge_folder']
            self.target_duration = self.config['merger']['target_duration'] * 60
            print_step(f"New settings loaded:")
            print_substep(f"Mode: {self.config['merger']['mode']}")
            print_substep(f"Status: {self.config['merger']['status']}")
            print_substep(f"Target duration: {self.config['merger']['target_duration']} minutes")
            if self.config['merger']['mode'] == 'specific':
                print_substep(f"Specific subreddit: {self.config['merger']['specific_subreddit']}")
            return True
        return False

    def load_config(self):
        """Load configuration from toml file"""
        try:
            with open("merger_config.toml", "r", encoding="utf-8") as f:
                return tomlkit.load(f)
        except FileNotFoundError:
            print_step("Config file not found. Creating default config...")
            self.create_default_config()
            return self.load_config()

    def create_default_config(self):
        """Create default configuration file"""
        doc = tomlkit.document()
        
        # Create merger table
        merger = tomlkit.table()
        merger.add("mode", "fastest")
        merger.add("specific_subreddit", "AmItheAsshole+relationship_advice+confession+tifu")
        merger.add("check_interval", 30)
        merger.add("target_duration", 10)
        merger.add("auto_process", True)
        merger.add("status", "running")  # Can be "running", "paused", or "stopping"
        doc.add("merger", merger)
        
        # Create paths table
        paths = tomlkit.table()
        paths.add("source_folder", r"C:\Users\buggy\Desktop\FullyAutomatedRedditVideoMakerBot-main\results")
        paths.add("merge_folder", "MergeVideo")
        doc.add("paths", paths)
        
        # Create processing table
        processing = tomlkit.table()
        processing.add("delete_source", False)
        processing.add("output_format", "mp4")
        processing.add("safe_mode", True)
        processing.add("finish_current_before_pause", True)
        doc.add("processing", processing)

        # Create splicing table
        splicing = tomlkit.table()
        splicing.add("min_silence_len", 500)  # milliseconds
        splicing.add("silence_thresh", -40)  # dB
        splicing.add("buffer_time", 0.5)  # seconds after title
        doc.add("splicing", splicing)

        with open("merger_config.toml", "w", encoding="utf-8") as f:
            f.write(tomlkit.dumps(doc))

    def detect_title_end(self, video_path):
        """Detect where the title reading ends based on audio analysis"""
        try:
            print_substep(f"Analyzing title end point for: {os.path.basename(video_path)}")
            
            # Extract audio from video
            temp_audio = "temp_audio.wav"
            command = [
                'ffmpeg', '-i', video_path,
                '-vn',  # Disable video
                '-acodec', 'pcm_s16le',  # Audio codec
                '-ar', '44100',  # Sample rate
                '-ac', '1',  # Mono audio
                temp_audio
            ]
            subprocess.run(command, capture_output=True)

            # Load audio and detect silence
            audio = AudioSegment.from_wav(temp_audio)
            
            # Get silence detection parameters from config
            min_silence_len = self.config['splicing']['min_silence_len']
            silence_thresh = self.config['splicing']['silence_thresh']
            buffer_time = self.config['splicing']['buffer_time']
            
            # Detect non-silent parts (speech)
            non_silent_ranges = detect_nonsilent(
                audio,
                min_silence_len=min_silence_len,
                silence_thresh=silence_thresh
            )

            # If we found speech segments
            if non_silent_ranges:
                # Title end is when first speech segment ends
                title_end = non_silent_ranges[0][1] / 1000.0  # Convert to seconds
                
                # Add buffer time from config
                title_end += buffer_time
                
                print_substep(f"Title end detected at {title_end:.2f} seconds")
                
                # Cleanup
                os.remove(temp_audio)
                return title_end
            else:
                print_substep("No clear title end point detected")
                return None

        except Exception as e:
            print_substep(f"Error detecting title end: {str(e)}")
            if os.path.exists("temp_audio.wav"):
                os.remove("temp_audio.wav")
            return None

    def splice_video(self, video_pair):
        """Create spliced version with clean intro and subtitled main content"""
        try:
            print_step(f"Creating spliced version for: {video_pair['name']}")
            
            # Get title end point from non-subtitled version
            title_end = self.detect_title_end(video_pair['files']['normal'])
            
            if not title_end:
                print_substep("Could not detect title end point. Using default 5 seconds.")
                title_end = 5.0
            
            # Load both video versions
            clean_video = VideoFileClip(video_pair['files']['normal'])
            subtitled_video = VideoFileClip(video_pair['files']['subtitled'])
            
            # Extract the intro from clean version
            intro = clean_video.subclip(0, title_end)
            
            # Get the rest from subtitled version
            main_content = subtitled_video.subclip(title_end)
            
            # Concatenate the clips
            final_clip = concatenate_videoclips([intro, main_content])
            
            # Create output filename
            output_path = os.path.join(self.merge_folder, f"{video_pair['name']}_spliced.mp4")
            
            # Write the final video
            final_clip.write_videofile(
                output_path,
                codec='libx264',
                audio_codec='aac',
                temp_audiofile='temp-audio.m4a',
                remove_temp=True
            )
            
            # Clean up
            clean_video.close()
            subtitled_video.close()
            final_clip.close()
            
            return output_path
            
        except Exception as e:
            print_substep(f"Error splicing video: {str(e)}")
            return None

    # [Previous methods remain the same: check_status, wait_with_status_check, etc.]

    def process_videos(self):
        """Process videos based on current mode"""
        # Check for config changes before processing
        if self.check_config_changed():
            if self.config['processing']['safe_mode']:
                print_step("Config changed during operation. Restarting process...")
                return None

        mode = self.config['merger']['mode']
        selected_pairs = None
        
        if mode == "fastest":
            selected_pairs = self.find_best_combination()
        elif mode == "specific":
            selected_pairs = self.process_specific_folder()
        else:
            print_step(f"Unknown mode: {mode}")
            return None
            
        if selected_pairs:
            # Process each selected pair
            spliced_videos = []
            for pair in selected_pairs:
                if spliced_path := self.splice_video(pair):
                    spliced_videos.append(spliced_path)
            
            return spliced_videos
        
        return None

    # [Rest of the previous code remains the same]

def main():
    compiler = VideoCompiler()
    print_step("Monitoring for config changes...")
    print_substep("You can modify merger_config.toml at any time to change settings")
    print_substep("Set status to 'paused' to pause, 'running' to resume, or 'stopping' to stop")

    while True:
        try:
            # Check status first
            if not compiler.check_status():
                print_step("Stopping process...")
                break

            # Check if auto-processing is still enabled
            compiler.check_config_changed()
            if not compiler.config['merger']['auto_process']:
                print_step("Auto-processing disabled in config. Exiting.")
                break

            processed_videos = compiler.process_videos()

            if processed_videos:
                print_step("\nProcessed Videos:")
                for video_path in processed_videos:
                    print_substep(f"Created: {os.path.basename(video_path)}")
                print_substep("-" * 50)

                # Here we'll add the final compilation code

                # Check status and wait
                check_interval = compiler.config['merger']['check_interval']
                if not compiler.wait_with_status_check(check_interval):
                    break
            else:
                print_step("No videos processed in this cycle.")
                check_interval = compiler.config['merger']['check_interval']
                if not compiler.wait_with_status_check(check_interval):
                    break

        except Exception as e:
            print_step(f"Error occurred: {str(e)}")
            print_step("Waiting 5 minutes before retrying...")
            if not compiler.wait_with_status_check(5):
                break

if __name__ == "__main__":
    main()