#!/usr/bin/env python3
import argparse
import os
import subprocess
import sys
from inspect_video import inspect_video, format_size

def parse_timecode(time_str, total_duration=None):
    """Parses a time string (seconds, MM:SS, HH:MM:SS, or 'last') into float seconds."""
    if not time_str:
        return 0.0
    time_str = time_str.strip().lower()

    if time_str == "last":
        if total_duration is None:
            raise ValueError("Total duration is required to calculate 'last' starting point.")
        target_dur = 10.0
        if total_duration <= target_dur:
            return 0.0
        return total_duration - target_dur

    if ":" in time_str:
        parts = time_str.split(":")
        if len(parts) == 2:  # MM:SS
            m, s = map(float, parts)
            return m * 60.0 + s
        elif len(parts) == 3:  # HH:MM:SS
            h, m, s = map(float, parts)
            return h * 3600.0 + m * 60.0 + s
        else:
            raise ValueError(f"Invalid timecode format: '{time_str}'. Use HH:MM:SS or MM:SS.")

    try:
        return float(time_str)
    except ValueError:
        raise ValueError(f"Invalid timecode: '{time_str}'. Must be float seconds, HH:MM:SS, or 'last'.")

def prep_video(input_path, output_path, start_time_str=None, duration=10, fps=None, resolution=None, strip_audio=False):
    """Preps a video file by trimming, optionally re-encoding to target fps and resolution."""
    if not os.path.exists(input_path):
        raise FileNotFoundError(f"Input file not found: {input_path}")

    # Check if ffmpeg is available
    try:
        subprocess.run(["ffmpeg", "-version"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, check=True)
    except (subprocess.SubprocessError, FileNotFoundError):
        raise RuntimeError("ffmpeg is not installed or not found in system PATH.")

    # Inspect input video first
    print(f"Analyzing source video: {os.path.basename(input_path)}...")
    source_info = inspect_video(input_path)
    total_duration = source_info.get("duration_seconds", 0.0)

    # Resolve start time
    if start_time_str is None:
        if total_duration and total_duration > 10.0 and sys.stdin.isatty():
            print(f"\nThe input video is longer than 10s ({total_duration:.2f}s).")
            print("Please choose a 10s segment to trim:")
            print("  1) First 10 seconds [default]")
            print("  2) Last 10 seconds")
            print("  3) Custom starting timecode (e.g., MM:SS, HH:MM:SS, or seconds)")
            try:
                choice = input("Your choice [1/2/3, default 1]: ").strip()
                if choice == "2":
                    start_time_str = "last"
                elif choice == "3":
                    custom_start = input("Enter starting timecode (e.g., 00:03 or 15): ").strip()
                    start_time_str = custom_start if custom_start else "0"
                else:
                    start_time_str = "0"
            except (KeyboardInterrupt, EOFError):
                print("\nNo input received. Defaulting to first 10 seconds.")
                start_time_str = "0"
        else:
            start_time_str = "0"

    try:
        start_seconds = parse_timecode(start_time_str, total_duration)
    except Exception as e:
        raise ValueError(f"Timecode parsing failed: {e}")


    if start_seconds < 0 or (total_duration and start_seconds >= total_duration):
        raise ValueError(f"Start time {start_seconds}s is out of bounds for video of length {total_duration}s.")

    # Construct output path if not specified
    if not output_path:
        os.makedirs("media", exist_ok=True)
        base_name = os.path.basename(input_path)
        name, ext = os.path.splitext(base_name)
        output_path = os.path.join("media", f"prepped_{name}.mp4")

    # Check if the source video file is large (>25MB)
    size_bytes_str = source_info.get("size_bytes")
    is_large = False
    try:
        if size_bytes_str and int(size_bytes_str) > 25 * 1024 * 1024:
            is_large = True
    except (ValueError, TypeError):
        pass

    # Target resolution parsing
    scale_filter = None
    orig_width = None
    orig_height = None
    if "video" in source_info:
        try:
            orig_width = int(source_info["video"].get("width"))
            orig_height = int(source_info["video"].get("height"))
        except (ValueError, TypeError):
            pass

    if resolution:
        try:
            target_w, target_h = map(int, resolution.lower().split("x"))
            if orig_width and orig_height:
                # Scale to fit target_w and target_h while preserving aspect ratio
                scale_factor = min(target_w / orig_width, target_h / orig_height)
                width = int(orig_width * scale_factor)
                height = int(orig_height * scale_factor)
            else:
                width, height = target_w, target_h
            # Ensure divisible by 2 for standard decoders/encoders
            width = (width // 2) * 2
            height = (height // 2) * 2
            scale_filter = f"scale={width}:{height}"
            resolution = f"{width}x{height}"
        except ValueError:
            raise ValueError(f"Invalid resolution: '{resolution}'. Format must be WIDTHxHEIGHT (e.g. 1280x720).")
    elif is_large:
        if orig_width and orig_height:
            # Scale down large videos proportionally (max 1280x720 for landscape, 720x1280 for portrait)
            if orig_width >= orig_height:
                max_w, max_h = 1280, 720
            else:
                max_w, max_h = 720, 1280
            scale_factor = min(max_w / orig_width, max_h / orig_height)
            if scale_factor < 1.0:
                width = int(orig_width * scale_factor)
                height = int(orig_height * scale_factor)
            else:
                width, height = orig_width, orig_height
        else:
            width, height = 1280, 720

        # Ensure divisible by 2
        width = (width // 2) * 2
        height = (height // 2) * 2
        resolution = f"{width}x{height}"
        print(f"\nRecommendation: Source video is very large ({source_info.get('file_size')}).")
        print("   Automatically scaling to optimize upload times for Gemini Omni Flash.")
        scale_filter = f"scale={width}:{height}"

    fps_spec = f"{fps} fps" if fps else "Original frame rate"
    print(f"\nPreparing Video Processing:")
    print(f"  * Source Duration: {total_duration:.2f}s")
    print(f"  * Trim Range     : Start at {start_seconds:.2f}s | Length {duration:.2f}s")
    if resolution:
        print(f"  * Encoding Specs : {width}x{height} @ {fps_spec}")
    else:
        print(f"  * Encoding Specs : Original Resolution @ {fps_spec}")
    print(f"  * Target Path    : {output_path}")
    print("=" * 50)

    # ffmpeg command construction
    cmd = [
        "ffmpeg",
        "-y",               # Overwrite output
        "-ss", str(start_seconds), # Seek start
        "-i", input_path,   # Input file
        "-t", str(duration), # Duration to copy
    ]
    if scale_filter:
        cmd.extend(["-vf", scale_filter])

    cmd.extend([
        "-c:v", "libx264",  # Standard H264 video codec
        "-pix_fmt", "yuv420p", # Standard pixel format for web/Gemini compatibility
    ])

    if fps:
        cmd.extend(["-r", str(fps)]) # Output frame rate if requested

    if strip_audio or not source_info.get("has_audio", False):
        if not source_info.get("has_audio", False) and not strip_audio:
            print("No audio stream detected in source video. Disabling audio output.")
        else:
            print("Stripping audio stream from video as requested.")
        cmd.append("-an")   # Disable audio streams completely
    else:
        cmd.extend([
            "-c:a", "aac",      # Convert audio to standard AAC
            "-b:a", "128k",     # Standard audio bitrate
            "-ac", "2",         # Convert to stereo
        ])

    cmd.append(output_path)

    print("Running ffmpeg encoding...")
    process = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)

    if process.returncode != 0:
        print("Error: ffmpeg failed. Stderr output follows:", file=sys.stderr)
        print(process.stderr, file=sys.stderr)
        raise RuntimeError("ffmpeg execution failed.")

    print("Video preparation completed successfully!")
    print("=" * 50)

    # Call inspection tool on output to print clean specs
    output_info = inspect_video(output_path)
    return output_info

def main():
    parser = argparse.ArgumentParser(description="Prep videos for editing (trimming, re-encoding to target fps and resolution).")
    parser.add_argument("file", help="Path to the source video file to prep")
    parser.add_argument("--start", "-s", default=None, help="Start timecode (seconds, MM:SS, HH:MM:SS, or 'last' for last 10s). Default: 0 (or prompted if > 10s)")
    parser.add_argument("--duration", "-d", type=int, default=10, help="Duration of trimmed segment in seconds. Default: 10")
    parser.add_argument("--fps", "-r", type=int, default=None, help="Target frame rate. Default: None (keep original frame rate)")
    parser.add_argument("--resolution", "-g", default=None, help="Target resolution (e.g., 1280x720). Default: None (keep original resolution)")
    parser.add_argument("--output", "-o", help="Custom output path. Defaults to media/prepped_<original_name>.mp4")
    parser.add_argument("--strip-audio", "-a", action="store_true", help="Completely strip/disable audio stream so the model can generate new audio")

    args = parser.parse_args()

    try:
        info = prep_video(
            input_path=args.file,
            output_path=args.output,
            start_time_str=args.start,
            duration=args.duration,
            fps=args.fps,
            resolution=args.resolution,
            strip_audio=args.strip_audio
        )

        # Display final output report
        print(f"\nPrepped Video Specifications: {info['file_name']}")
        print("=" * 50)
        print(f"File Size   : {info['file_size']}")
        print(f"Duration    : {info['duration']}")
        print(f"Bitrate     : {info['bitrate']}")
        print(f"Resolution  : {info['video']['resolution']}")
        print(f"Frame Rate  : {info['video']['fps']}")
        print(f"Video Codec : {info['video']['codec']}")
        if info["has_audio"]:
            print(f"Audio Spec  : {info['audio']['codec']} | {info['audio']['channels']} ch | {info['audio']['sample_rate']}")
        print()

    except Exception as e:
        print(f"Error prepping video: {e}", file=sys.stderr)
        sys.exit(1)

if __name__ == "__main__":
    main()
