"""
Command-line interface for FMUS-VID.

This module provides a comprehensive CLI for video processing operations.
"""

import argparse
import sys
import logging
import os
from pathlib import Path
from typing import List, Optional
import time

# Add the parent directory to system path to allow importing fmusvid package
script_dir = os.path.dirname(os.path.abspath(__file__))
package_dir = os.path.dirname(os.path.dirname(script_dir))
if package_dir not in sys.path:
    sys.path.insert(0, package_dir)

from rich.console import Console
from rich.progress import Progress, SpinnerColumn, TextColumn, BarColumn, TimeElapsedColumn
import fmusvid

logger = logging.getLogger(__name__)
console = Console()

def setup_logging(verbose: bool):
    """Configure logging level."""
    level = logging.DEBUG if verbose else logging.INFO
    logging.basicConfig(level=level, format='%(levelname)s: %(message)s')

def create_parser() -> argparse.ArgumentParser:
    """Create command-line argument parser."""
    parser = argparse.ArgumentParser(
        description="FMUS-VID: Human-centric video processing tool"
    )

    parser.add_argument(
        "--verbose", "-v",
        action="store_true",
        help="Enable verbose output"
    )

    subparsers = parser.add_subparsers(dest="command", help="Command to execute")

    # Info command
    info_parser = subparsers.add_parser("info", help="Display video information")
    info_parser.add_argument("input", help="Input video file")

    # Convert command
    convert_parser = subparsers.add_parser("convert", help="Convert video format")
    convert_parser.add_argument("input", help="Input video file")
    convert_parser.add_argument("output", help="Output video file")
    convert_parser.add_argument(
        "--codec", "-c",
        help="Video codec (e.g., h264, hevc)"
    )
    convert_parser.add_argument(
        "--preset", "-p",
        help="Encoding preset (e.g., fast, slow)"
    )
    convert_parser.add_argument(
        "--bitrate", "-b",
        help="Video bitrate (e.g., 5M)"
    )

    # Trim command
    trim_parser = subparsers.add_parser("trim", help="Trim video")
    trim_parser.add_argument("input", help="Input video file")
    trim_parser.add_argument("output", help="Output video file")
    trim_parser.add_argument(
        "--start", "-s",
        type=float,
        help="Start time in seconds"
    )
    trim_parser.add_argument(
        "--end", "-e",
        type=float,
        help="End time in seconds"
    )

    # Resize command
    resize_parser = subparsers.add_parser("resize", help="Resize video")
    resize_parser.add_argument("input", help="Input video file")
    resize_parser.add_argument("output", help="Output video file")
    resize_parser.add_argument(
        "--width", "-w",
        type=int,
        help="Output width"
    )
    resize_parser.add_argument(
        "--height", "--height-px",
        type=int,
        help="Output height"
    )
    resize_parser.add_argument(
        "--keep-aspect",
        action="store_true",
        help="Maintain aspect ratio"
    )

    # Concat command
    concat_parser = subparsers.add_parser("concat", help="Concatenate videos")
    concat_parser.add_argument(
        "inputs",
        nargs="+",
        help="Input video files"
    )
    concat_parser.add_argument("output", help="Output video file")

    # Grid command
    grid_parser = subparsers.add_parser("grid", help="Create video grid")
    grid_parser.add_argument(
        "inputs",
        nargs="+",
        help="Input video files"
    )
    grid_parser.add_argument("output", help="Output video file")
    grid_parser.add_argument(
        "--rows", "-r",
        type=int,
        required=True,
        help="Number of rows"
    )
    grid_parser.add_argument(
        "--cols", "-c",
        type=int,
        required=True,
        help="Number of columns"
    )

    # Effects command
    effects_parser = subparsers.add_parser("effects", help="Apply video effects")
    effects_parser.add_argument("input", help="Input video file")
    effects_parser.add_argument("output", help="Output video file")
    effects_parser.add_argument(
        "--grayscale",
        action="store_true",
        help="Convert to grayscale"
    )
    effects_parser.add_argument(
        "--blur",
        type=float,
        help="Apply blur (radius)"
    )
    effects_parser.add_argument(
        "--brightness",
        type=float,
        help="Adjust brightness (1.0 = original)"
    )
    effects_parser.add_argument(
        "--contrast",
        type=float,
        help="Adjust contrast (1.0 = original)"
    )

    # Audio command
    audio_parser = subparsers.add_parser("audio", help="Audio operations")
    audio_parser.add_argument("input", help="Input video file")
    audio_parser.add_argument("output", help="Output video file")
    audio_parser.add_argument(
        "--volume",
        type=float,
        help="Set volume (1.0 = original)"
    )
    audio_parser.add_argument(
        "--mute",
        action="store_true",
        help="Remove audio"
    )
    audio_parser.add_argument(
        "--add-audio",
        help="Add audio file"
    )

    # Analyze command
    analyze_parser = subparsers.add_parser("analyze", help="Analyze video")
    analyze_parser.add_argument("input", help="Input video file")
    analyze_parser.add_argument(
        "--detect-scenes",
        action="store_true",
        help="Detect scene changes"
    )
    analyze_parser.add_argument(
        "--detect-objects",
        action="store_true",
        help="Detect objects (requires AI models)"
    )
    analyze_parser.add_argument(
        "--analyze-audio",
        action="store_true",
        help="Analyze audio characteristics"
    )

    # NEW COMMANDS BELOW

    # Screen capture command
    capture_parser = subparsers.add_parser("capture", help="Capture screenshot")
    capture_parser.add_argument(
        "output",
        help="Output image file"
    )
    capture_parser.add_argument(
        "--region", "-r",
        nargs=4,
        type=int,
        metavar=("LEFT", "TOP", "RIGHT", "BOTTOM"),
        help="Region to capture (left top right bottom)"
    )
    capture_parser.add_argument(
        "--select",
        action="store_true",
        help="Interactively select region to capture"
    )

    # Screen recording command
    record_parser = subparsers.add_parser("record", help="Record screen to video")
    record_parser.add_argument(
        "output",
        help="Output video file"
    )
    record_parser.add_argument(
        "--region", "-r",
        nargs=4,
        type=int,
        metavar=("LEFT", "TOP", "RIGHT", "BOTTOM"),
        help="Region to record (left top right bottom)"
    )
    record_parser.add_argument(
        "--select",
        action="store_true",
        help="Interactively select region to record"
    )
    record_parser.add_argument(
        "--duration", "-d",
        type=float,
        help="Recording duration in seconds"
    )
    record_parser.add_argument(
        "--fps",
        type=float,
        default=30.0,
        help="Frames per second"
    )
    record_parser.add_argument(
        "--audio", "-a",
        action="store_true",
        help="Record audio"
    )

    # Images to video command
    images2video_parser = subparsers.add_parser("images2video", help="Convert image sequence to video")
    images2video_parser.add_argument(
        "inputs",
        nargs="+",
        help="Input image files or directory"
    )
    images2video_parser.add_argument(
        "output",
        help="Output video file"
    )
    images2video_parser.add_argument(
        "--fps",
        type=float,
        default=30.0,
        help="Frames per second"
    )
    images2video_parser.add_argument(
        "--pattern",
        help="Filename pattern for image sequence (e.g., 'frame_*.jpg')"
    )

    # Video to images command
    video2images_parser = subparsers.add_parser("video2images", help="Extract frames from video")
    video2images_parser.add_argument(
        "input",
        help="Input video file"
    )
    video2images_parser.add_argument(
        "output_dir",
        help="Output directory for images"
    )
    video2images_parser.add_argument(
        "--fps",
        type=float,
        help="Frames per second to extract (default: video's fps)"
    )
    video2images_parser.add_argument(
        "--format", "-f",
        default="png",
        choices=["jpg", "png", "bmp", "tiff"],
        help="Output image format"
    )
    video2images_parser.add_argument(
        "--prefix",
        default="frame_",
        help="Filename prefix for extracted frames"
    )
    video2images_parser.add_argument(
        "--start", "-s",
        type=float,
        help="Start time in seconds"
    )
    video2images_parser.add_argument(
        "--end", "-e",
        type=float,
        help="End time in seconds"
    )
    video2images_parser.add_argument(
        "--with-timestamp",
        action="store_true",
        help="Add timestamp overlay to extracted frames"
    )

    # Thumbnails command
    thumbnails_parser = subparsers.add_parser("thumbnails", help="Generate thumbnails from video")
    thumbnails_parser.add_argument(
        "input",
        help="Input video file"
    )
    thumbnails_parser.add_argument(
        "output",
        help="Output image file or directory"
    )
    thumbnails_parser.add_argument(
        "--count", "-c",
        type=int,
        default=9,
        help="Number of thumbnails to generate"
    )
    thumbnails_parser.add_argument(
        "--grid",
        action="store_true",
        default=True,
        help="Create grid of thumbnails (default: True)"
    )
    thumbnails_parser.add_argument(
        "--scale",
        type=float,
        default=0.25,
        help="Scale factor for thumbnails"
    )

    # Side-by-side videos command
    sidebyside_parser = subparsers.add_parser("sidebyside", help="Combine videos side by side")
    sidebyside_parser.add_argument(
        "inputs",
        nargs="+",
        help="Input video files"
    )
    sidebyside_parser.add_argument(
        "output",
        help="Output video file"
    )

    # Reverse video command
    reverse_parser = subparsers.add_parser("reverse", help="Reverse video playback")
    reverse_parser.add_argument(
        "input",
        help="Input video file"
    )
    reverse_parser.add_argument(
        "output",
        help="Output video file"
    )

    return parser

def progress_callback(progress: float):
    """Update progress bar."""
    if hasattr(progress_callback, 'progress_bar'):
        progress_callback.progress_bar.update(
            progress_callback.task_id,
            completed=int(progress * 100)
        )

def cmd_info(args):
    """Handle info command."""
    try:
        video = fmusvid.load(args.input)
        info = video.get_info()

        console.print("\n[bold]Video Information:[/bold]")
        console.print(f"Path: {args.input}")
        console.print(f"Duration: {info['duration']:.2f} seconds")
        console.print(f"Dimensions: {info['width']}x{info['height']}")
        console.print(f"FPS: {info['fps']:.2f}")
        console.print(f"Codec: {info['codec']}")
        if info['audio_codec']:
            console.print(f"Audio Codec: {info['audio_codec']}")
        console.print(f"Bitrate: {info['bitrate']}")

    except Exception as e:
        logger.error(f"Failed to get video info: {e}")
        sys.exit(1)

def cmd_convert(args):
    """Handle convert command."""
    try:
        with Progress(
            SpinnerColumn(),
            TextColumn("[progress.description]{task.description}"),
            BarColumn(),
            TextColumn("[progress.percentage]{task.percentage:>3.0f}%"),
            TimeElapsedColumn()
        ) as progress:
            progress_callback.progress_bar = progress
            progress_callback.task_id = progress.add_task(
                "Converting video...",
                total=100
            )

            video = fmusvid.load(args.input)
            video.save(
                args.output,
                codec=args.codec,
                preset=args.preset,
                bitrate=args.bitrate,
                progress_callback=progress_callback
            )

    except Exception as e:
        logger.error(f"Failed to convert video: {e}")
        sys.exit(1)

def cmd_trim(args):
    """Handle trim command."""
    try:
        with Progress() as progress:
            progress_callback.progress_bar = progress
            progress_callback.task_id = progress.add_task(
                "Trimming video...",
                total=100
            )

            video = fmusvid.load(args.input)
            video.trim(args.start, args.end)
            video.save(args.output, progress_callback=progress_callback)

    except Exception as e:
        logger.error(f"Failed to trim video: {e}")
        sys.exit(1)

def cmd_resize(args):
    """Handle resize command."""
    try:
        with Progress() as progress:
            progress_callback.progress_bar = progress
            progress_callback.task_id = progress.add_task(
                "Resizing video...",
                total=100
            )

            video = fmusvid.load(args.input)
            video.resize(
                width=args.width,
                height=args.height,
                keep_aspect=args.keep_aspect
            )
            video.save(args.output, progress_callback=progress_callback)

    except Exception as e:
        logger.error(f"Failed to resize video: {e}")
        sys.exit(1)

def cmd_concat(args):
    """Handle concat command."""
    try:
        with Progress() as progress:
            progress_callback.progress_bar = progress
            progress_callback.task_id = progress.add_task(
                "Concatenating videos...",
                total=100
            )

            videos = [fmusvid.load(path) for path in args.inputs]
            result = fmusvid.concat(videos)
            result.save(args.output, progress_callback=progress_callback)

    except Exception as e:
        logger.error(f"Failed to concatenate videos: {e}")
        sys.exit(1)

def cmd_grid(args):
    """Handle grid command."""
    try:
        with Progress() as progress:
            progress_callback.progress_bar = progress
            progress_callback.task_id = progress.add_task(
                "Creating video grid...",
                total=100
            )

            videos = [fmusvid.load(path) for path in args.inputs]
            result = fmusvid.grid(videos, args.rows, args.cols)
            result.save(args.output, progress_callback=progress_callback)

    except Exception as e:
        logger.error(f"Failed to create video grid: {e}")
        sys.exit(1)

def cmd_effects(args):
    """Handle effects command."""
    try:
        with Progress() as progress:
            progress_callback.progress_bar = progress
            progress_callback.task_id = progress.add_task(
                "Applying effects...",
                total=100
            )

            video = fmusvid.load(args.input)

            if args.grayscale:
                video.grayscale()
            if args.blur is not None:
                video.blur(args.blur)
            if args.brightness is not None:
                video.brightness(args.brightness)
            if args.contrast is not None:
                video.contrast(args.contrast)

            video.save(args.output, progress_callback=progress_callback)

    except Exception as e:
        logger.error(f"Failed to apply effects: {e}")
        sys.exit(1)

def cmd_audio(args):
    """Handle audio command."""
    try:
        with Progress() as progress:
            progress_callback.progress_bar = progress
            progress_callback.task_id = progress.add_task(
                "Processing audio...",
                total=100
            )

            video = fmusvid.load(args.input)

            if args.mute:
                video.mute()
            if args.volume is not None:
                video.volume(args.volume)
            if args.add_audio:
                video.add_audio(args.add_audio)

            video.save(args.output, progress_callback=progress_callback)

    except Exception as e:
        logger.error(f"Failed to process audio: {e}")
        sys.exit(1)

def cmd_analyze(args):
    """Handle analyze command."""
    try:
        video = fmusvid.load(args.input)

        if args.detect_scenes:
            console.print("\n[bold]Scene Detection:[/bold]")
            scenes = video.detect_scenes()
            for i, (start, end) in enumerate(scenes, 1):
                console.print(f"Scene {i}: {start:.2f}s - {end:.2f}s")

        if args.detect_objects:
            console.print("\n[bold]Object Detection:[/bold]")
            objects = video.detect_objects()
            for obj in objects:
                console.print(f"Found {obj['label']} ({obj['confidence']:.2%})")

        if args.analyze_audio:
            console.print("\n[bold]Audio Analysis:[/bold]")
            audio_info = video.analyze_audio()
            console.print(f"Average volume: {audio_info['volume_rms']:.2f} dB")
            console.print(f"Peak volume: {audio_info['volume_peak']:.2f} dB")
            console.print(f"Tempo: {audio_info['tempo']:.1f} BPM")

    except Exception as e:
        logger.error(f"Failed to analyze video: {e}")
        sys.exit(1)

def cmd_capture(args):
    """Handle capture command."""
    try:
        region = None

        # If --select flag is specified, use interactive selection
        if args.select:
            console.print("Select a region to capture...")
            region = fmusvid.select_region()
        # If --region argument is provided, use those coordinates
        elif args.region:
            region = tuple(args.region)

        # Capture screen or region
        if region:
            console.print(f"Capturing region {region}...")
            result = fmusvid.capture_region(region, args.output)
        else:
            console.print("Capturing full screen...")
            result = fmusvid.capture_screen(args.output)

        console.print(f"Screenshot saved to: {result}")

    except Exception as e:
        logger.error(f"Failed to capture screen: {e}")
        sys.exit(1)

def cmd_record(args):
    """Handle record command."""
    try:
        region = None

        # If --select flag is specified, use interactive selection
        if args.select:
            console.print("Select a region to record...")
            region = fmusvid.select_region()
        # If --region argument is provided, use those coordinates
        elif args.region:
            region = tuple(args.region)

        with Progress() as progress:
            progress_callback.progress_bar = progress
            progress_callback.task_id = progress.add_task(
                "Recording...",
                total=100
            )

            # Record screen or region
            if region:
                console.print(f"Recording region {region}...")
                video = fmusvid.record_region(
                    args.output,
                    region=region,
                    duration=args.duration,
                    fps=args.fps,
                    audio=args.audio,
                    progress_callback=progress_callback
                )
            else:
                console.print("Recording full screen...")
                video = fmusvid.record_screen(
                    args.output,
                    duration=args.duration,
                    fps=args.fps,
                    audio=args.audio,
                    progress_callback=progress_callback
                )

            console.print(f"Screen recording saved to: {video.path}")

    except Exception as e:
        logger.error(f"Failed to record screen: {e}")
        sys.exit(1)

def cmd_images2video(args):
    """Handle images to video command."""
    try:
        with Progress() as progress:
            progress_callback.progress_bar = progress
            progress_callback.task_id = progress.add_task(
                "Converting images to video...",
                total=100
            )

            # Check if a single directory was provided
            if len(args.inputs) == 1 and os.path.isdir(args.inputs[0]):
                input_dir = args.inputs[0]
                pattern = args.pattern or "*.*"
                console.print(f"Using images from directory: {input_dir} with pattern: {pattern}")
                video = fmusvid.images_to_video(
                    os.path.join(input_dir, pattern),
                    args.output,
                    fps=args.fps,
                    progress_callback=progress_callback
                )
            else:
                # Multiple image files specified
                console.print(f"Converting {len(args.inputs)} images to video...")
                video = fmusvid.images_to_video(
                    args.inputs,
                    args.output,
                    fps=args.fps,
                    progress_callback=progress_callback
                )

            console.print(f"Video created at: {args.output}")

    except Exception as e:
        logger.error(f"Failed to convert images to video: {e}")
        sys.exit(1)

def cmd_video2images(args):
    """Handle video to images command."""
    try:
        with Progress() as progress:
            progress_callback.progress_bar = progress
            progress_callback.task_id = progress.add_task(
                "Extracting frames...",
                total=100
            )

            # Create output directory if it doesn't exist
            os.makedirs(args.output_dir, exist_ok=True)

            console.print(f"Extracting frames from {args.input}...")
            paths = fmusvid.video_to_images(
                args.input,
                args.output_dir,
                prefix=args.prefix,
                format=args.format,
                start=args.start,
                end=args.end,
                fps=args.fps,
                with_timestamp=args.with_timestamp,
                progress_callback=progress_callback
            )

            console.print(f"Extracted {len(paths)} frames to: {args.output_dir}")

    except Exception as e:
        logger.error(f"Failed to extract frames: {e}")
        sys.exit(1)

def cmd_thumbnails(args):
    """Handle thumbnails command."""
    try:
        console.print(f"Generating thumbnails from {args.input}...")

        video = fmusvid.load(args.input)
        result = fmusvid.create_thumbnails(
            video,
            count=args.count,
            output_path=args.output,
            grid=args.grid,
            scale=args.scale
        )

        if isinstance(result, list):
            console.print(f"Generated {len(result)} thumbnails to: {args.output}")
        else:
            console.print(f"Generated thumbnail grid at: {result}")

    except Exception as e:
        logger.error(f"Failed to generate thumbnails: {e}")
        sys.exit(1)

def cmd_sidebyside(args):
    """Handle side-by-side command."""
    try:
        with Progress() as progress:
            progress_callback.progress_bar = progress
            progress_callback.task_id = progress.add_task(
                "Creating side-by-side video...",
                total=100
            )

            console.print(f"Combining {len(args.inputs)} videos side by side...")

            # Load all videos
            videos = [fmusvid.load(path) for path in args.inputs]

            # Create side-by-side video
            result = fmusvid.side_by_side(videos)

            # Save the result
            result.save(args.output, progress_callback=progress_callback)

            console.print(f"Side-by-side video saved to: {args.output}")

    except Exception as e:
        logger.error(f"Failed to create side-by-side video: {e}")
        sys.exit(1)

def cmd_reverse(args):
    """Handle reverse command."""
    try:
        with Progress() as progress:
            progress_callback.progress_bar = progress
            progress_callback.task_id = progress.add_task(
                "Reversing video...",
                total=100
            )

            console.print(f"Reversing video: {args.input}...")

            # Load video
            video = fmusvid.load(args.input)

            # Reverse video
            reversed_video = fmusvid.reverse_video(video)

            # Save the result
            reversed_video.save(args.output, progress_callback=progress_callback)

            console.print(f"Reversed video saved to: {args.output}")

    except Exception as e:
        logger.error(f"Failed to reverse video: {e}")
        sys.exit(1)

def main():
    """Main CLI entry point."""
    parser = create_parser()
    args = parser.parse_args()

    if not args.command:
        parser.print_help()
        sys.exit(1)

    setup_logging(args.verbose)

    # Command mapping
    commands = {
        "info": cmd_info,
        "convert": cmd_convert,
        "trim": cmd_trim,
        "resize": cmd_resize,
        "concat": cmd_concat,
        "grid": cmd_grid,
        "effects": cmd_effects,
        "audio": cmd_audio,
        "analyze": cmd_analyze,
        "capture": cmd_capture,
        "record": cmd_record,
        "images2video": cmd_images2video,
        "video2images": cmd_video2images,
        "thumbnails": cmd_thumbnails,
        "sidebyside": cmd_sidebyside,
        "reverse": cmd_reverse
    }

    # Execute command
    commands[args.command](args)

if __name__ == "__main__":
    main()
