use anyhow::Result;
use std::env;
use std::io::Write;
#[cfg(feature = "player")]
use std::os::unix::io::AsRawFd;
use std::path::{Path, PathBuf};
use std::process::{Child, Command, Stdio};

mod api_client;
mod asr_overlay;
mod chunk_selector;
mod selector;

use api_client::ApiClient;
use selector::{VideoEntry, VideoSelector};

#[allow(dead_code)]
const STATUS_BAR_HEIGHT: i32 = 50;
#[allow(dead_code)]
const FONT_SIZE: i32 = 20;
#[allow(dead_code)]
const ASR_OVERLAY_HEIGHT: i32 = 80;

#[derive(Debug, Clone, Copy)]
#[allow(dead_code)]
enum TerminalCommand {
    Pause,
    Sound,
    SeekBackward,
    SeekForward,
    ToggleStatusBar,
    ToggleAsr,
    Download,
    SyncIncrease,
    SyncDecrease,
    Quit,
}

#[derive(Debug, Clone, Copy)]
#[allow(dead_code)]
struct VideoInfo {
    width: u32,
    height: u32,
    fps: f64,
    total_frames: u64,
    duration: f64,
}

#[allow(dead_code)]
struct PlayerState {
    current_time: f64,
    current_frame: u64,
    is_paused: bool,
    sound_on: bool,
    quit: bool,
    status_bar_visible: bool,
    asr_overlay_visible: bool,
}

struct Config {
    download_dir: PathBuf,
}

#[allow(dead_code)]
fn start_sound_process(stream_url: &str, start_time: f64) -> Option<Child> {
    Command::new(if cfg!(target_os = "macos") {
        "/opt/homebrew/bin/ffplay"
    } else {
        "ffplay"
    })
    .args([
        "-nodisp",
        "-autoexit",
        "-ss",
        &format!("{:.2}", start_time),
        stream_url,
    ])
    .spawn()
    .ok()
}

#[allow(dead_code)]
struct FormatOption {
    format_id: String,
    resolution: String,
    ext: String,
    note: String,
    filesize: String,
}

#[allow(dead_code)]
fn load_config() -> Config {
    let config_path = PathBuf::from(env::var("HOME").unwrap_or_default())
        .join(".config")
        .join("video_player")
        .join("config.toml");

    if config_path.exists() {
        if let Ok(content) = std::fs::read_to_string(&config_path) {
            for line in content.lines() {
                let line = line.trim();
                if line.starts_with("download_dir") && line.contains('=') {
                    let value = line.split('=').nth(1).unwrap_or("").trim();
                    let path = value
                        .trim_matches('"')
                        .replace("~", &env::var("HOME").unwrap_or_default());
                    return Config {
                        download_dir: PathBuf::from(path),
                    };
                }
            }
        }
    }

    Config {
        download_dir: PathBuf::from(env::var("HOME").unwrap_or_default()).join("Downloads"),
    }
}

#[allow(dead_code)]
fn list_available_formats(video_url: &str) -> Result<Vec<FormatOption>> {
    println!("Fetching available formats...");
    let output = Command::new("yt-dlp")
        .args(["-F", "--no-download", video_url])
        .output()?;

    if !output.status.success() {
        let stderr = String::from_utf8_lossy(&output.stderr);
        anyhow::bail!("Failed to list formats: {}", stderr);
    }

    let stdout = String::from_utf8_lossy(&output.stdout);
    let mut formats = Vec::new();

    for line in stdout.lines() {
        let line = line.trim();
        if line.is_empty()
            || line.starts_with("ID")
            || line.starts_with("---")
            || line.contains("storyboard")
        {
            continue;
        }

        if let Some(first_part) = line.split('|').next() {
            let parts: Vec<&str> = first_part.split_whitespace().collect();
            if parts.len() >= 3 {
                let format_id = parts[0].to_string();
                let ext = parts[1].to_string();
                let resolution = parts[2].to_string();

                if ext == "mp4" || ext == "webm" || ext == "m4a" {
                    if !resolution.contains("x") {
                        continue;
                    }

                    let note = if line.contains("|") {
                        line.split('|')
                            .nth(1)
                            .map(|s| s.trim().to_string())
                            .unwrap_or_default()
                    } else {
                        String::new()
                    };

                    formats.push(FormatOption {
                        format_id,
                        resolution,
                        ext,
                        note,
                        filesize: String::new(),
                    });
                }
            }
        }
    }

    formats.sort_by(|a, b| {
        let a_h = a
            .resolution
            .split('x')
            .nth(1)
            .unwrap_or("0")
            .parse::<u32>()
            .unwrap_or(0);
        let b_h = b
            .resolution
            .split('x')
            .nth(1)
            .unwrap_or("0")
            .parse::<u32>()
            .unwrap_or(0);
        b_h.cmp(&a_h)
    });

    Ok(formats)
}

#[allow(dead_code)]
fn show_format_menu(formats: &[FormatOption], term_fd: libc::c_int) -> Option<usize> {
    for (i, fmt) in formats.iter().enumerate().take(10) {
        println!("[{}] {} {} ({})", i + 1, fmt.resolution, fmt.ext, fmt.note);
    }
    println!("----------------------------------------");
    print!("Enter choice (default: 1): ");

    if std::io::stdout().flush().is_err() {
        return None;
    }

    unsafe {
        let mut termios = std::mem::zeroed();
        libc::tcgetattr(term_fd, &mut termios);
        let mut normal = termios;
        libc::cfmakeraw(&mut normal);
        libc::tcsetattr(term_fd, libc::TCSANOW, &normal);

        let mut input = String::new();
        let result = std::io::stdin().read_line(&mut input);

        libc::tcsetattr(term_fd, libc::TCSANOW, &termios);

        if result.is_ok() {
            let input = input.trim();
            if input.is_empty() {
                return Some(0);
            }
            if let Ok(choice) = input.parse::<usize>() {
                if choice >= 1 && choice <= formats.len() {
                    return Some(choice - 1);
                }
            }
        }
    }
    None
}

fn download_video(video_url: &str, format_id: &str, download_dir: &Path) -> Result<String> {
    println!("Downloading video to {:?}...", download_dir);

    std::fs::create_dir_all(download_dir)?;

    let output = Command::new("yt-dlp")
        .args([
            "-f",
            format_id,
            "-o",
            &format!("{}/%(title)s.%(ext)s", download_dir.display()),
            video_url,
        ])
        .output()?;

    if !output.status.success() {
        let stderr = String::from_utf8_lossy(&output.stderr);
        anyhow::bail!("Download failed: {}", stderr);
    }

    let stdout = String::from_utf8_lossy(&output.stdout);
    for line in stdout.lines() {
        if line.contains("Merging")
            || line.contains("Destination")
            || line.contains(".mp4")
            || line.contains(".webm")
        {
            if let Some(path) = line.split("Destination: ").nth(1) {
                let path = path.trim();
                if Path::new(path).exists() {
                    return Ok(path.to_string());
                }
            }
            if line.contains(".mp4") || line.contains(".webm") {
                let filename = line.split_whitespace().last().unwrap_or("");
                let full_path = download_dir.join(filename);
                if full_path.exists() {
                    return Ok(full_path.to_string_lossy().to_string());
                }
            }
        }
    }

    for entry in (std::fs::read_dir(download_dir)?).flatten() {
        let path = entry.path();
        let ext = path.extension().and_then(|e| e.to_str()).unwrap_or("");
        if ext == "mp4" || ext == "webm" || ext == "mkv" {
            return Ok(path.to_string_lossy().to_string());
        }
    }

    anyhow::bail!("Could not find downloaded file")
}

fn is_youtube_url(input: &str) -> bool {
    input.starts_with("http://")
        || input.starts_with("https://")
        || input.contains("youtube.com")
        || input.contains("youtu.be")
}

#[allow(dead_code)]
fn get_youtube_stream_url(video_url: &str) -> Result<String> {
    println!("Getting video stream from YouTube...");
    let output = Command::new("yt-dlp")
        .args(["-f", "best[ext=mp4][vcodec!=none]", "-g", video_url])
        .output()?;

    if !output.status.success() {
        let output = Command::new("yt-dlp")
            .args(["-f", "best", "-g", video_url])
            .output()?;
        if !output.status.success() {
            let stderr = String::from_utf8_lossy(&output.stderr);
            anyhow::bail!("yt-dlp failed: {}", stderr);
        }
        let url = String::from_utf8_lossy(&output.stdout).trim().to_string();
        if url.is_empty() {
            anyhow::bail!("yt-dlp returned empty URL");
        }
        println!("Stream URL obtained");
        return Ok(url);
    }

    let url = String::from_utf8_lossy(&output.stdout).trim().to_string();
    if url.is_empty() {
        anyhow::bail!("yt-dlp returned empty URL");
    }
    println!("Stream URL obtained");
    Ok(url)
}

#[allow(dead_code)]
fn get_video_info(video_path: &str) -> Result<VideoInfo> {
    let output = Command::new("ffprobe")
        .args([
            "-v",
            "error",
            "-select_streams",
            "v:0",
            "-show_entries",
            "stream=width,height,r_frame_rate,nb_frames,duration",
            "-of",
            "json",
            video_path,
        ])
        .output();

    match output {
        Ok(output) if output.status.success() => {
            let json_str = String::from_utf8_lossy(&output.stdout);
            if let Ok(json) = serde_json::from_str::<serde_json::Value>(&json_str) {
                let stream = &json["streams"][0];
                return Ok(VideoInfo {
                    width: stream["width"].as_u64().unwrap_or(1280) as u32,
                    height: stream["height"].as_u64().unwrap_or(720) as u32,
                    fps: parse_fps(stream["r_frame_rate"].as_str().unwrap_or("30/1")),
                    total_frames: stream["nb_frames"].as_u64().unwrap_or(0),
                    duration: stream["duration"]
                        .as_str()
                        .and_then(|s| s.parse::<f64>().ok())
                        .unwrap_or(0.0),
                });
            }
        }
        _ => {}
    }

    Ok(VideoInfo {
        width: 1280,
        height: 720,
        fps: 30.0,
        total_frames: 0,
        duration: 0.0,
    })
}

#[allow(dead_code)]
fn parse_fps(fps_str: &str) -> f64 {
    let parts: Vec<&str> = fps_str.split('/').collect();
    if parts.len() == 2 {
        let num: f64 = parts[0].parse().unwrap_or(30.0);
        let den: f64 = parts[1].parse().unwrap_or(1.0);
        if den > 0.0 {
            num / den
        } else {
            30.0
        }
    } else {
        fps_str.parse().unwrap_or(30.0)
    }
}

#[allow(dead_code)]
fn format_time(seconds: f64) -> String {
    let hours = (seconds / 3600.0).floor() as u32;
    let minutes = ((seconds % 3600.0) / 60.0).floor() as u32;
    let secs = (seconds % 60.0).floor() as u32;
    let millis = ((seconds % 1.0) * 100.0).floor() as u32;
    format!("{:02}:{:02}:{:02}.{:02}", hours, minutes, secs, millis)
}

#[allow(dead_code)]
fn get_video_duration(video_path: &str) -> f64 {
    let output = std::process::Command::new("ffprobe")
        .args([
            "-v",
            "error",
            "-show_entries",
            "format=duration",
            "-of",
            "default=noprint_wrappers=1:nokey=1",
            video_path,
        ])
        .output();

    match output {
        Ok(out) if out.status.success() => {
            let duration_str = String::from_utf8_lossy(&out.stdout).trim().to_string();
            duration_str.parse::<f64>().unwrap_or(0.0)
        }
        _ => 0.0,
    }
}

fn lookup_video_uuid(video_path: &str) -> Option<String> {
    use std::process::Command as StdCommand;

    // Try to find UUID from database by matching file_path
    let output = StdCommand::new("psql")
        .args([
            "-U",
            "accusys",
            "-h",
            "localhost",
            "-d",
            "momentry",
            "-t",
            "-A",
            "-c",
            &format!(
                "SELECT uuid FROM videos WHERE file_path LIKE '%{}%' LIMIT 1",
                video_path.split('/').next_back().unwrap_or("")
            ),
        ])
        .output()
        .ok()?;

    if output.status.success() {
        let uuid = String::from_utf8_lossy(&output.stdout).trim().to_string();
        if !uuid.is_empty() {
            return Some(uuid);
        }
    }

    None
}

#[allow(dead_code)]
#[cfg(not(feature = "player"))]
fn draw_status_bar(
    _video_info: &VideoInfo,
    _state: &PlayerState,
    _sync_delay_ms: u64,
) -> Result<String> {
    Ok(format!(
        "{:.2}s / {:.2}s",
        _state.current_time, _video_info.duration
    ))
}

#[allow(dead_code)]
#[cfg(feature = "player")]
fn draw_status_bar(
    _canvas: &mut (),
    _font: &(),
    _video_info: &VideoInfo,
    _state: &PlayerState,
    _sync_delay_ms: u64,
) -> Result<String> {
    Ok(format!(
        "{:.2}s / {:.2}s",
        _state.current_time, _video_info.duration
    ))
}

#[allow(dead_code)]
fn start_ffmpeg(
    stream_url: &str,
    video_width: u32,
    video_height: u32,
    video_fps: f64,
    seek_time: f64,
) -> Result<Child> {
    let ffmpeg_path = if cfg!(target_os = "macos") {
        "/opt/homebrew/bin/ffmpeg"
    } else {
        "ffmpeg"
    };
    let fps_str = format!("{:.2}", video_fps);

    let mut cmd = Command::new(ffmpeg_path);

    if seek_time > 0.0 {
        cmd.args(["-ss", &format!("{:.2}", seek_time)]);
    }

    cmd.args([
        "-i",
        stream_url,
        "-vf",
        &format!(
            "scale={}:{}:force_original_aspect_ratio=decrease",
            video_width, video_height
        ),
        "-f",
        "rawvideo",
        "-pix_fmt",
        "rgb24",
        "-r",
        &fps_str,
        "-",
    ])
    .stdout(Stdio::piped())
    .stderr(Stdio::null())
    .spawn()
    .map_err(|e| anyhow::anyhow!("Failed to start ffmpeg: {}", e))
}

#[cfg(not(feature = "player"))]
fn run_player(_video_path: &str, _video_uuid: Option<String>) -> Result<()> {
    println!("Player not available - SDL2 not configured");
    println!("Playing: {} (UUID: {:?})", _video_path, _video_uuid);
    println!("(This is a stub - full player requires SDL2)");
    Ok(())
}

#[cfg(feature = "player")]
fn run_player(video_path: &str, video_uuid: Option<String>) -> Result<()> {
    run_player_with_sdl2(video_path, video_uuid)
}

#[cfg(feature = "player")]
fn run_player_with_sdl2(video_path: &str, video_uuid: Option<String>) -> Result<()> {
    use sdl2::event::Event;
    use sdl2::keyboard::Keycode;
    use sdl2::pixels::PixelFormatEnum;
    use std::io::{BufReader, Read};
    use std::sync::atomic::{AtomicBool, Ordering};
    use std::sync::Arc;
    use std::thread;
    use std::time::{Duration, Instant};

    println!("\n=== 🎬 SDL2 Video Player ===");
    println!("File: {}", video_path);
    println!("UUID: {:?}", video_uuid);

    let sdl_context = sdl2::init().map_err(|e| anyhow::anyhow!("SDL init failed: {}", e))?;
    let video_subsystem = sdl_context
        .video()
        .map_err(|e| anyhow::anyhow!("Video init failed: {}", e))?;

    let width = 1280u32;
    let height = 720u32;

    let window = video_subsystem
        .window("Momentry Player", width, height)
        .position_centered()
        .resizable()
        .build()
        .map_err(|e| anyhow::anyhow!("Window creation failed: {}", e))?;

    let mut canvas = window
        .into_canvas()
        .build()
        .map_err(|e| anyhow::anyhow!("Canvas creation failed: {}", e))?;

    let texture_creator = canvas.texture_creator();
    let mut texture = texture_creator
        .create_texture_streaming(PixelFormatEnum::RGB24, width as u32, height as u32)
        .map_err(|e| anyhow::anyhow!("Texture creation failed: {}", e))?;

    let ffmpeg_path = if cfg!(target_os = "macos") {
        "/opt/homebrew/bin/ffmpeg"
    } else {
        "ffmpeg"
    };

    let mut ffmpeg = std::process::Command::new(ffmpeg_path)
        .args([
            "-i",
            video_path,
            "-vf",
            &format!(
                "scale={}:{}:force_original_aspect_ratio=decrease,pad={}:{}:(ow-iw)/2:(oh-ih)/2",
                width, height, width, height
            ),
            "-pix_fmt",
            "rgb24",
            "-r",
            "30",
            "-f",
            "rawvideo",
            "-",
        ])
        .stdout(std::process::Stdio::piped())
        .stderr(std::process::Stdio::null())
        .spawn()
        .map_err(|e| anyhow::anyhow!("Failed to start ffmpeg: {}", e))?;

    let stdout = ffmpeg
        .stdout
        .take()
        .ok_or_else(|| anyhow::anyhow!("Failed to capture stdout"))?;
    let mut reader = BufReader::new(stdout);

    let frame_size = (width * height * 3) as usize;
    let mut frame_buffer = vec![0u8; frame_size];

    let playing = Arc::new(AtomicBool::new(true));
    let playing_clone = playing.clone();

    let mut event_pump = sdl_context
        .event_pump()
        .map_err(|e| anyhow::anyhow!("Event pump failed: {}", e))?;

    let mut asr_overlay = asr_overlay::AsrOverlay::new();
    let _ = asr_overlay.load_from_file(video_path);
    println!("ASR Overlay initialized: {}", !asr_overlay.is_empty());

    let video_duration = get_video_duration(video_path);
    println!("Video duration: {:.1}s", video_duration);

    let mut frame_count = 0u64;
    let frame_duration = Duration::from_millis(33);
    let mut paused = false;
    let mut current_time = 0.0;
    let mut seek_request: Option<f64> = None;
    let fps = 30.0;

    let mut asr_overlay_visible = false;

    println!("Playing... (Press SPACE to pause, Q/ESC to quit, ←/→ to seek, A to toggle ASR, F for fullscreen)");

    loop {
        let frame_start = Instant::now();

        // Handle seek by restarting ffmpeg
        if let Some(seek_pos) = seek_request {
            seek_request = None;
            println!("\n⏩ Seeking to {:.1}s...", seek_pos);

            // Kill old ffmpeg and restart with seek position
            let _ = ffmpeg.kill();

            ffmpeg = std::process::Command::new(ffmpeg_path)
                .args([
                    "-ss", &format!("{:.2}", seek_pos),
                    "-i", video_path,
                    "-vf", &format!(
                        "scale={}:{}:force_original_aspect_ratio=decrease,pad={}:{}:(ow-iw)/2:(oh-ih)/2",
                        width, height, width, height
                    ),
                    "-pix_fmt", "rgb24",
                    "-r", "30",
                    "-f", "rawvideo",
                    "-",
                ])
                .stdout(std::process::Stdio::piped())
                .stderr(std::process::Stdio::null())
                .spawn()
                .map_err(|e| anyhow::anyhow!("Failed to restart ffmpeg: {}", e))?;

            let stdout = ffmpeg
                .stdout
                .take()
                .ok_or_else(|| anyhow::anyhow!("Failed to capture stdout"))?;
            reader = BufReader::new(stdout);
            current_time = seek_pos;
            println!("▶ Resumed at {:.1}s", current_time);
        }

        for event in event_pump.poll_iter() {
            match event {
                Event::Quit { .. } => {
                    println!("\n👋 Quitting player");
                    playing_clone.store(false, Ordering::SeqCst);
                    break;
                }
                Event::KeyDown { keycode, .. } => match keycode {
                    Some(Keycode::Q) | Some(Keycode::Escape) => {
                        println!("\n👋 Quitting player");
                        playing_clone.store(false, Ordering::SeqCst);
                        break;
                    }
                    Some(Keycode::Space) => {
                        paused = !paused;
                        println!("{}", if paused { "⏸ Paused" } else { "▶ Playing" });
                    }
                    Some(Keycode::Left) => {
                        let new_time = (current_time - 10.0).max(0.0);
                        seek_request = Some(new_time);
                        println!("⏪ Seek to {:.1}s", new_time);
                    }
                    Some(Keycode::Right) => {
                        let new_time = current_time + 10.0;
                        seek_request = Some(new_time);
                        println!("⏩ Seek to {:.1}s", new_time);
                    }
                    Some(Keycode::Up) => {
                        let new_time = (current_time - 60.0).max(0.0);
                        seek_request = Some(new_time);
                        println!("⏪ Seek to {:.1}s (1min)", new_time);
                    }
                    Some(Keycode::Down) => {
                        let new_time = current_time + 60.0;
                        seek_request = Some(new_time);
                        println!("⏩ Seek to {:.1}s (+1min)", new_time);
                    }
                    Some(Keycode::A) => {
                        // Toggle ASR Visibility
                        asr_overlay_visible = !asr_overlay_visible;
                        println!(
                            "{}",
                            if asr_overlay_visible {
                                "🔊 ASR ON"
                            } else {
                                "🔇 ASR OFF"
                            }
                        );
                    }
                    Some(Keycode::F) => {
                        println!("📺 Toggle fullscreen (not implemented in basic SDL2)");
                    }
                    _ => {}
                },
                _ => {}
            }
        }

        if !playing_clone.load(Ordering::SeqCst) {
            break;
        }

        if paused {
            thread::sleep(Duration::from_millis(100));
            continue;
        }

        // Update ASR text based on current time
        if !asr_overlay.is_empty() {
            asr_overlay.update(current_time);
        }

        match reader.read_exact(&mut frame_buffer) {
            Ok(_) => {
                texture
                    .update(None, &frame_buffer, (width * 3) as usize)
                    .map_err(|e| anyhow::anyhow!("Texture update failed: {}", e))?;

                // Draw everything
                canvas.clear();

                canvas
                    .copy(&texture, None, None)
                    .map_err(|e| anyhow::anyhow!("Render failed: {}", e))?;

                // Draw ASR Text if visible and available
                if asr_overlay_visible && !asr_overlay.get_text().is_empty() {
                    // Placeholder: Cannot use TTF functions directly here without font context.
                    // For now, just printing to console to verify timing.
                    // In a real implementation, load font and draw text here.
                    println!("[ASR] {:.1}s: {}", current_time, asr_overlay.get_text());
                }

                // Draw progress bar at bottom - gray background, green progress
                use sdl2::rect::Rect;
                let progress = if video_duration > 0.0 {
                    (current_time / video_duration).min(1.0)
                } else {
                    0.0
                };
                let bar_width = ((width as f64) * progress) as u32;

                canvas.set_draw_color(sdl2::pixels::Color::RGB(50, 50, 50)); // Background
                let _ = canvas.fill_rect(Rect::new(0, height as i32 - 15, width, 5));
                if bar_width > 0 {
                    canvas.set_draw_color(sdl2::pixels::Color::RGB(0, 200, 0)); // Progress
                    let _ = canvas.fill_rect(Rect::new(0, height as i32 - 15, bar_width, 5));
                }
                // Reset draw color to black for next frame
                canvas.set_draw_color(sdl2::pixels::Color::RGB(0, 0, 0));

                canvas.present();

                frame_count += 1;
                current_time += 1.0 / fps;

                let elapsed = frame_start.elapsed();
                if elapsed < frame_duration {
                    thread::sleep(frame_duration - elapsed);
                }
            }
            Err(_) => {
                println!(
                    "\n📽️ End of video ({} frames, {:.1}s)",
                    frame_count, current_time
                );
                break;
            }
        }
    }

    let _ = ffmpeg.kill();
    println!("✅ Playback finished (total: {:.1}s)", current_time);
    Ok(())
}

fn run_local_mode(external_player: &str) -> Result<()> {
    let args: Vec<String> = env::args().collect();

    // Find video path - skip all flags and get the first non-flag argument after them
    let video_path = args
        .iter()
        .skip(1) // Skip binary name
        .skip_while(|a| a.starts_with('-')) // Skip flags
        .next()
        .cloned();

    let video_path = match video_path {
        Some(p) if !p.is_empty() => p,
        _ => {
            println!("Local Mode - Play local video files");
            println!("=====================================\n");
            print!("Enter video file path: ");
            let mut input = String::new();
            std::io::stdin().read_line(&mut input)?;
            let path = input.trim().to_string();
            if path.is_empty() {
                anyhow::bail!("No video path provided");
            }
            path
        }
    };

    if !Path::new(&video_path).exists() {
        anyhow::bail!("File not found: {}", video_path);
    }

    println!("\nUsing external player: {}", external_player);
    println!("Playing: {}", video_path);

    match external_player {
        "vlc" => {
            std::process::Command::new("open")
                .arg("-a")
                .arg("VLC")
                .arg(&video_path)
                .spawn()?;
            println!("✅ Opened with VLC");
        }
        "mpv" => {
            std::process::Command::new("mpv").arg(&video_path).spawn()?;
            println!("✅ Opened with mpv");
        }
        "ffplay" => {
            std::process::Command::new("ffplay")
                .arg("-autoexit")
                .arg(&video_path)
                .spawn()?;
            println!("✅ Opened with ffplay");
        }
        "sdl2" => {
            #[cfg(feature = "player")]
            return run_player_with_sdl2(&video_path, None);
            #[cfg(not(feature = "player"))]
            {
                println!("SDL2 player not enabled. Rebuild with --features player");
            }
        }
        _ => {
            std::process::Command::new(external_player)
                .arg(&video_path)
                .spawn()?;
            println!("✅ Opened with {}", external_player);
        }
    }

    Ok(())
}

fn run_online_mode() -> Result<()> {
    println!("\n===========================================");
    println!("         🎬 Online Mode - Momentry");
    println!("===========================================\n");

    let client = ApiClient::new();
    println!("Connected to API: {}", client.base_url());

    let rt = tokio::runtime::Runtime::new()?;

    loop {
        println!("\n┌─────────────────────────────────────────┐");
        println!("│         Online Mode Menu                │");
        println!("├─────────────────────────────────────────┤");
        println!("│  [1] List Videos  - 列出所有影片       │");
        println!("│  [2] Search       - RAG 搜尋影片內容  │");
        println!("│  [3] Play          - 播放影片           │");
        println!("│  [4] Lookup        - 查詢影片資訊      │");
        println!("│  [q] Quit          - 離開               │");
        println!("└─────────────────────────────────────────┘");
        print!("\n請選擇: ");

        let mut input = String::new();
        std::io::stdin().read_line(&mut input)?;
        let choice = input.trim();

        match choice {
            "1" => {
                println!("\n=== 📋 影片列表 ===");
                match rt.block_on(client.list_videos()) {
                    Ok(videos) => {
                        if videos.is_empty() {
                            println!("沒有找到任何影片");
                        } else {
                            println!("\n共 {} 部影片:\n", videos.len());
                            for (i, v) in videos.iter().enumerate() {
                                let duration = format!(
                                    "{}:{:02}",
                                    (v.duration / 60.0) as u32,
                                    (v.duration % 60.0) as u32
                                );
                                println!(
                                    "  [{}] {} | {} | {}x{} | {}",
                                    i + 1,
                                    v.file_name,
                                    v.uuid.chars().take(8).collect::<String>(),
                                    v.width,
                                    v.height,
                                    duration
                                );
                            }
                        }
                    }
                    Err(e) => println!("取得影片列表失敗: {}", e),
                }
            }
            "2" => {
                println!("\n=== 🔍 RAG 搜尋 ===");
                print!("輸入搜尋關鍵字: ");
                input.clear();
                std::io::stdin().read_line(&mut input)?;
                let query = input.trim().to_string();
                if query.is_empty() {
                    println!("搜尋關鍵字不能為空");
                    continue;
                }

                print!("限定特定影片？(y/N): ");
                input.clear();
                std::io::stdin().read_line(&mut input)?;
                let limit_uuid = if input.trim().to_lowercase() == "y" {
                    print!("輸入影片 UUID: ");
                    input.clear();
                    std::io::stdin().read_line(&mut input)?;
                    Some(input.trim().to_string())
                } else {
                    None
                };

                println!("\n搜尋中...");
                match rt.block_on(client.search_chunks(&query, limit_uuid.as_deref(), Some(10))) {
                    Ok(response) => {
                        if response.results.is_empty() {
                            println!("沒有找到結果");
                            continue;
                        }
                        println!("\n找到 {} 個結果:\n", response.results.len());
                        for (i, r) in response.results.iter().enumerate() {
                            let time_range = format!(
                                "{:02}:{:02} - {:02}:{:02}",
                                (r.start_time / 60.0) as u32,
                                (r.start_time % 60.0) as u32,
                                (r.end_time / 60.0) as u32,
                                (r.end_time % 60.0) as u32
                            );
                            let text_preview = if r.text.len() > 50 {
                                format!("{}...", &r.text[..50])
                            } else {
                                r.text.clone()
                            };
                            println!(
                                "  [{}] {} | {} | {:.2} | {}",
                                i + 1,
                                time_range,
                                r.uuid.chars().take(8).collect::<String>(),
                                r.score,
                                text_preview
                            );
                        }

                        let mut current_player: Option<std::process::Child> = None;

                        loop {
                            if let Some(ref mut child) = current_player {
                                match child.try_wait() {
                                    Ok(Some(_)) => {
                                        println!("播放器已結束");
                                        current_player = None;
                                    }
                                    Ok(None) => {
                                        // 還在執行中
                                    }
                                    Err(e) => {
                                        println!("檢查播放器狀態失敗：{}", e);
                                        current_player = None;
                                    }
                                }
                            }

                            print!(
                                "\n選擇播放 (1-{}) 或 q 離開 (kill player), L 重新顯示列表：",
                                response.results.len()
                            );
                            input.clear();
                            std::io::stdin().read_line(&mut input)?;
                            let selection = input.trim();
                            let selection_lower = selection.to_lowercase();
                            if selection_lower == "q" {
                                if let Some(ref mut child) = current_player {
                                    let _ = child.kill();
                                    let _ = child.wait();
                                    println!("已終止播放器");
                                    current_player = None;
                                }
                                break;
                            }
                            if selection_lower == "l" {
                                println!("\n搜尋結果:");
                                for (i, r) in response.results.iter().enumerate() {
                                    let time_range = format!(
                                        "{:02}:{:02} - {:02}:{:02}",
                                        (r.start_time / 60.0) as u32,
                                        (r.start_time % 60.0) as u32,
                                        (r.end_time / 60.0) as u32,
                                        (r.end_time % 60.0) as u32
                                    );
                                    let text_preview = if r.text.len() > 50 {
                                        format!("{}...", &r.text[..50])
                                    } else {
                                        r.text.clone()
                                    };
                                    println!(
                                        "  [{}] {} | {} | {:.2} | {}",
                                        i + 1,
                                        time_range,
                                        r.uuid.chars().take(8).collect::<String>(),
                                        r.score,
                                        text_preview
                                    );
                                }
                                continue;
                            }
                            if let Ok(idx) = selection.parse::<usize>() {
                                if idx > 0 && idx <= response.results.len() {
                                    let selected = &response.results[idx - 1];
                                    println!("\n播放：{} - {}", selected.uuid, selected.text);

                                    if let Some(ref mut child) = current_player {
                                        let _ = child.kill();
                                        let _ = child.wait();
                                        println!("已終止前一個播放器");
                                    }

                                    match rt.block_on(client.lookup_video(&selected.uuid)) {
                                        Ok(info) => {
                                            if let Some(path) = &info.file_path {
                                                if std::path::Path::new(path).exists() {
                                                    let start_sec =
                                                        (selected.start_time as f64) - 2.0;
                                                    let end_sec = (selected.end_time as f64) + 2.0;
                                                    println!(
                                                        "開啟：{} (從 {:.0} 到 {:.0} 秒，A-B 循環)",
                                                        path, start_sec, end_sec
                                                    );
                                                    println!("提示：mpv 視窗中按 c/C 切換循環，q 離開，Space 暫停");
                                                    current_player = Some(
                                                        std::process::Command::new("mpv")
                                                            .arg(format!(
                                                                "--start={:.2}",
                                                                start_sec.max(0.0)
                                                            ))
                                                            .arg(format!(
                                                                "--ab-loop-a={:.2}",
                                                                start_sec.max(0.0)
                                                            ))
                                                            .arg(format!("--ab-loop-b={:.2}", end_sec))
                                                            .arg("--input-commands=bind c ab-loop; bind C ab-loop")
                                                            .arg(path)
                                                            .spawn()?
                                                    );
                                                } else {
                                                    println!("錯誤：檔案不存在：{}", path);
                                                }
                                            }
                                        }
                                        Err(e) => println!("查詢失敗：{}", e),
                                    }
                                }
                            }
                        }
                    }
                    Err(e) => println!("搜尋失敗：{}", e),
                }
            }
            "4" => {
                println!("\n=== 🔎 查詢影片 ===");
                print!("輸入影片 UUID (直接 Enter 從列表選擇): ");
                input.clear();
                std::io::stdin().read_line(&mut input)?;
                let uuid = input.trim();

                if uuid.is_empty() {
                    println!("載入影片列表...");
                    match rt.block_on(client.list_videos()) {
                        Ok(videos) => {
                            if videos.is_empty() {
                                println!("沒有影片");
                                continue;
                            }
                            println!("\n選擇影片:");
                            for (i, v) in videos.iter().enumerate() {
                                println!("  [{}] {} ({})", i + 1, v.file_name, v.uuid);
                            }
                            print!("\n選擇編號：");
                            input.clear();
                            std::io::stdin().read_line(&mut input)?;
                            if let Ok(idx) = input.trim().parse::<usize>() {
                                if idx > 0 && idx <= videos.len() {
                                    let selected = &videos[idx - 1];
                                    println!("\n查詢中...");
                                    match rt.block_on(client.lookup_video(&selected.uuid)) {
                                        Ok(info) => {
                                            println!("\n✓ 找到影片:");
                                            println!("  UUID: {}", info.uuid);
                                            if let Some(path) = &info.file_path {
                                                println!("  路徑：{}", path);
                                            }
                                            if let Some(name) = &info.file_name {
                                                println!("  名稱：{}", name);
                                            }
                                            if let Some(dur) = info.duration {
                                                println!("  時長：{:.2}s", dur);
                                            }
                                        }
                                        Err(e) => println!("查詢失敗：{}", e),
                                    }
                                }
                            }
                        }
                        Err(e) => println!("取得影片列表失敗：{}", e),
                    }
                } else {
                    println!("\n查詢中...");
                    match rt.block_on(client.lookup_video(uuid)) {
                        Ok(info) => {
                            println!("\n✓ 找到影片:");
                            println!("  UUID: {}", info.uuid);
                            if let Some(path) = &info.file_path {
                                println!("  路徑：{}", path);
                            }
                            if let Some(name) = &info.file_name {
                                println!("  名稱：{}", name);
                            }
                            if let Some(dur) = info.duration {
                                println!("  時長：{:.2}s", dur);
                            }
                        }
                        Err(e) => println!("查詢失敗：{}", e),
                    }
                }
            }
            "3" => {
                println!("\n=== ▶ 播放影片 ===");
                print!("輸入影片 UUID (直接 Enter 從列表選擇): ");
                input.clear();
                std::io::stdin().read_line(&mut input)?;
                let uuid = input.trim();

                if uuid.is_empty() {
                    println!("載入影片列表...");
                    match rt.block_on(client.list_videos()) {
                        Ok(videos) => {
                            if videos.is_empty() {
                                println!("沒有影片");
                                continue;
                            }
                            println!("\n選擇影片:");
                            for (i, v) in videos.iter().enumerate() {
                                println!("  [{}] {} ({})", i + 1, v.file_name, v.uuid);
                            }
                            print!("\n選擇編號：");
                            input.clear();
                            std::io::stdin().read_line(&mut input)?;
                            if let Ok(idx) = input.trim().parse::<usize>() {
                                if idx > 0 && idx <= videos.len() {
                                    let selected = &videos[idx - 1];
                                    println!("\n播放: {}", selected.file_path);
                                    if std::path::Path::new(&selected.file_path).exists() {
                                        std::process::Command::new("mpv")
                                            .arg(&selected.file_path)
                                            .spawn()?;
                                    } else {
                                        println!("錯誤：檔案不存在：{}", selected.file_path);
                                    }
                                }
                            }
                        }
                        Err(e) => println!("取得影片列表失敗：{}", e),
                    }
                } else {
                    match rt.block_on(client.lookup_video(uuid)) {
                        Ok(info) => {
                            if let Some(path) = &info.file_path {
                                println!("開啟: {}", path);
                                if std::path::Path::new(path).exists() {
                                    std::process::Command::new("mpv").arg(path).spawn()?;
                                } else {
                                    println!("錯誤：檔案不存在：{}", path);
                                }
                            }
                        }
                        Err(e) => println!("查詢失敗：{}", e),
                    }
                }
            }
            "q" | "Q" => {
                println!("\n👋 再見!");
                break;
            }
            _ => {
                println!("無效選項");
            }
        }
    }

    Ok(())
}

fn main() -> Result<()> {
    env_logger::init();
    let args: Vec<String> = env::args().collect();

    let should_download = args.iter().any(|a| a == "-d" || a == "--download");
    let show_selector = args.iter().any(|a| a == "-s" || a == "--selector");
    let test_api_mode = args.iter().any(|a| a == "-t" || a == "--test-api");
    let local_mode = args.iter().any(|a| a == "-l" || a == "--local");
    let online_mode = args.iter().any(|a| a == "-o" || a == "--online");

    // Get external player choice
    let external_player = args
        .iter()
        .position(|a| a == "-p" || a == "--player")
        .and_then(|i| args.get(i + 1))
        .cloned()
        .unwrap_or_else(|| "vlc".to_string());

    // API Testing Mode
    if test_api_mode {
        return run_api_test_mode();
    }

    // If --selector flag is provided, show video selector (online mode)
    if show_selector {
        return run_selector();
    }

    // If --online or -o is provided, run online mode
    if online_mode {
        return run_online_mode();
    }

    // If --local or -l is provided, run local mode with external player
    if local_mode {
        return run_local_mode(&external_player);
    }

    let video_path = if args.len() < 2 || (should_download && args.len() < 3) {
        println!("Video Player\n============\nEnter video path or YouTube URL:");
        let mut input = String::new();
        std::io::stdin().read_line(&mut input)?;
        let trimmed = input.trim().to_string();
        if trimmed.is_empty() {
            anyhow::bail!("No input provided");
        }
        trimmed
    } else {
        let idx = if should_download { 2 } else { 1 };
        args[idx].clone()
    };

    println!("Video Player\n============\nInput: {}", video_path);

    let final_path = if should_download && is_youtube_url(&video_path) {
        println!("Downloading with best quality...");
        let config = load_config();
        let format_id = "best[ext=mp4][vcodec!=none]";
        match download_video(&video_path, format_id, &config.download_dir) {
            Ok(local_path) => {
                println!("Download complete: {}", local_path);
                Some(local_path)
            }
            Err(e) => {
                eprintln!("Download failed: {}, playing stream instead", e);
                None
            }
        }
    } else {
        None
    };

    let play_path = final_path.unwrap_or(video_path);

    if is_youtube_url(&play_path) {
        println!("Source: YouTube");
    } else if Path::new(&play_path).exists() {
        println!("Source: Local file");
    } else {
        anyhow::bail!("File not found: {}", play_path);
    }

    let video_uuid = lookup_video_uuid(&play_path);
    println!("Video UUID: {:?}", video_uuid);
    run_player(&play_path, video_uuid)?;
    Ok(())
}

fn run_selector() -> Result<()> {
    use std::process::Command as StdCommand;

    let _db_url = momentry_core::core::config::DATABASE_URL.as_str();

    // Use psql to query videos
    let output = StdCommand::new("psql")
        .args(["-U", "accusys", "-h", "localhost", "-d", "momentry", "-t", "-A", 
               "-c", "SELECT uuid, file_name, file_path, duration, width, height FROM videos ORDER BY created_at DESC"])
        .output();

    let videos: Vec<VideoEntry> = match output {
        Ok(out) if out.status.success() => {
            let stdout = String::from_utf8_lossy(&out.stdout);
            stdout
                .lines()
                .filter(|line| !line.is_empty())
                .filter_map(|line| {
                    let parts: Vec<&str> = line.split('|').collect();
                    if parts.len() >= 6 {
                        Some(VideoEntry {
                            uuid: parts[0].to_string(),
                            file_name: parts[1].to_string(),
                            file_path: parts[2].to_string(),
                            duration: parts[3].parse().unwrap_or(0.0),
                            width: parts[4].parse().unwrap_or(0),
                            height: parts[5].parse().unwrap_or(0),
                            thumbnail_dir: None,
                        })
                    } else {
                        None
                    }
                })
                .collect()
        }
        _ => {
            // Fallback: scan directory
            println!("Could not connect to database, scanning directory...");
            let test_video_dir = PathBuf::from("/Users/accusys/momentry_core_project/test_video");
            std::fs::read_dir(&test_video_dir)?
                .filter_map(|e| e.ok())
                .filter(|e| {
                    let path = e.path();
                    matches!(
                        path.extension().and_then(|s| s.to_str()),
                        Some("mp4") | Some("mov") | Some("m4v") | Some("avi")
                    )
                })
                .map(|e| {
                    let path = e.path();
                    VideoEntry {
                        uuid: format!("{:x}", md5::compute(path.to_string_lossy().as_bytes()))
                            [0..16]
                            .to_string(),
                        file_name: path
                            .file_name()
                            .unwrap_or_default()
                            .to_string_lossy()
                            .to_string(),
                        file_path: path.to_string_lossy().to_string(),
                        duration: 0.0,
                        width: 0,
                        height: 0,
                        thumbnail_dir: None,
                    }
                })
                .collect()
        }
    };

    if videos.is_empty() {
        println!("No videos found. Register videos first with 'momentry register'");
        return Ok(());
    }

    // Try interactive mode, fall back to list if not a terminal
    if atty::is(atty::Stream::Stdout) {
        println!("Found {} videos", videos.len());

        let mut selector = VideoSelector::new(videos);
        match selector.run() {
            Ok(Some(video)) => {
                println!("\nPlaying: {} ({})", video.file_name, video.uuid);
                run_player(&video.file_path, Some(video.uuid))?;
            }
            Ok(None) => {
                println!("\nNo video selected");
            }
            Err(e) => {
                eprintln!("Selector error: {}", e);
            }
        }
    } else {
        // Non-interactive: show list
        println!("\nAvailable videos:");
        for (i, video) in videos.iter().enumerate() {
            println!(
                "  {}) {} - {} ({})",
                i + 1,
                video.file_name,
                video.format_duration(),
                video.uuid
            );
        }
        println!("\nRun with a video path to play, or use interactive mode in a terminal.");
    }

    Ok(())
}

fn run_api_test_mode() -> Result<()> {
    println!("\n===========================================");
    println!("         🎬 API Testing GUI");
    println!("===========================================\n");

    let client = ApiClient::new();
    println!("API Server: {}\n", client.base_url());

    println!(
        "Waiting for API server... (make sure 'cargo run --bin momentry -- server' is running)\n"
    );

    let rt = tokio::runtime::Runtime::new()?;

    loop {
        println!("\n┌─────────────────────────────────────────┐");
        println!("│           Main Menu                     │");
        println!("├─────────────────────────────────────────┤");
        println!("│  [1] Search     - 自然語言搜尋影片內容  │");
        println!("│  [2] List       - 列出所有影片          │");
        println!("│  [3] Register   - 註冊新影片           │");
        println!("│  [4] Lookup     - 查詢影片資訊        │");
        println!("│  [5] Play       - 播放影片             │");
        println!("│  [q] Quit       - 離開                 │");
        println!("└─────────────────────────────────────────┘");
        print!("\n請選擇: ");

        let mut input = String::new();
        std::io::stdin().read_line(&mut input)?;
        let choice = input.trim();

        match choice {
            "1" => {
                println!("\n=== 🔍 自然語言搜尋 ===");
                print!("輸入搜尋關鍵字: ");
                input.clear();
                std::io::stdin().read_line(&mut input)?;
                let query = input.trim().to_string();
                if query.is_empty() {
                    println!("搜尋關鍵字不能為空");
                    continue;
                }

                print!("是否限定特定影片？(y/N): ");
                input.clear();
                std::io::stdin().read_line(&mut input)?;
                let limit_uuid = if input.trim().to_lowercase() == "y" {
                    print!("輸入影片 UUID: ");
                    input.clear();
                    std::io::stdin().read_line(&mut input)?;
                    Some(input.trim().to_string())
                } else {
                    None
                };

                println!("\n搜尋中...");
                match rt.block_on(client.search_chunks(&query, limit_uuid.as_deref(), Some(20))) {
                    Ok(response) => {
                        println!("\n找到 {} 個結果:\n", response.results.len());
                        for (i, r) in response.results.iter().enumerate() {
                            let time_range = format!(
                                "{:02}:{:02} - {:02}:{:02}",
                                (r.start_time / 60.0) as u32,
                                (r.start_time % 60.0) as u32,
                                (r.end_time / 60.0) as u32,
                                (r.end_time % 60.0) as u32
                            );
                            let text_preview = if r.text.len() > 60 {
                                format!("{}...", &r.text[..60])
                            } else {
                                r.text.clone()
                            };
                            println!(
                                "  [{}] {} | {} | {:.2} | {}",
                                i + 1,
                                time_range,
                                r.uuid.chars().take(8).collect::<String>(),
                                r.score,
                                text_preview
                            );
                        }

                        if !response.results.is_empty() {
                            print!("\n選擇要播放的結果編號 (直接Enter跳過): ");
                            input.clear();
                            std::io::stdin().read_line(&mut input)?;
                            if let Ok(idx) = input.trim().parse::<usize>() {
                                if idx > 0 && idx <= response.results.len() {
                                    let selected = &response.results[idx - 1];
                                    println!("\n正在取得影片路徑...");
                                    match rt.block_on(client.lookup_video(&selected.uuid)) {
                                        Ok(info) => {
                                            if let Some(path) = &info.file_path {
                                                println!(
                                                    "播放: {} @ {:.2}s",
                                                    path, selected.start_time
                                                );
                                                let video_uuid = Some(selected.uuid.clone());
                                                run_player(path, video_uuid)?;
                                            } else {
                                                println!("無法取得影片路徑");
                                            }
                                        }
                                        Err(e) => println!("查詢失敗: {}", e),
                                    }
                                }
                            }
                        }
                    }
                    Err(e) => println!("搜尋失敗: {}", e),
                }
            }
            "2" => {
                println!("\n=== 📋 影片列表 ===");
                println!("載入中...");
                match rt.block_on(client.list_videos()) {
                    Ok(videos) => {
                        if videos.is_empty() {
                            println!("沒有找到任何影片，請先註冊");
                        } else {
                            println!("\n共 {} 部影片:\n", videos.len());
                            for (i, v) in videos.iter().enumerate() {
                                let duration = format!(
                                    "{}:{:02}",
                                    (v.duration / 60.0) as u32,
                                    (v.duration % 60.0) as u32
                                );
                                println!(
                                    "  [{}] {} | {} | {}x{} | {}",
                                    i + 1,
                                    v.file_name,
                                    v.uuid.chars().take(8).collect::<String>(),
                                    v.width,
                                    v.height,
                                    duration
                                );
                            }
                        }
                    }
                    Err(e) => println!("取得影片列表失敗: {}", e),
                }
            }
            "3" => {
                println!("\n=== 📝 註冊影片 ===");
                print!("輸入影片檔案路徑 (直接Enter使用自動搜尋): ");
                input.clear();
                std::io::stdin().read_line(&mut input)?;
                let path = input.trim();

                let video_path = if path.is_empty() {
                    println!("自動搜尋影片...");
                    match api_client::find_video_path() {
                        Some(p) => {
                            println!("找到: {}", p);
                            p
                        }
                        None => {
                            println!("找不到影片檔案，請手動輸入路徑");
                            continue;
                        }
                    }
                } else {
                    path.to_string()
                };

                if !std::path::Path::new(&video_path).exists() {
                    println!("檔案不存在: {}", video_path);
                    continue;
                }

                println!("\n註冊中...");
                match rt.block_on(client.register_video(&video_path)) {
                    Ok(resp) => {
                        println!("\n✓ 註冊成功!");
                        println!("  UUID: {}", resp.uuid);
                        println!("  名稱: {}", resp.file_name);
                        println!("  時長: {:.2}s", resp.duration);
                        println!("  解析度: {}x{}", resp.width, resp.height);
                    }
                    Err(e) => println!("註冊失敗: {}", e),
                }
            }
            "4" => {
                print!("\n=== 🔎 查詢影片 ===\n輸入影片 UUID: ");
                input.clear();
                std::io::stdin().read_line(&mut input)?;
                let uuid = input.trim();
                if uuid.is_empty() {
                    println!("UUID 不能為空");
                    continue;
                }

                println!("\n查詢中...");
                match rt.block_on(client.lookup_video(uuid)) {
                    Ok(info) => {
                        println!("\n✓ 找到影片:");
                        println!("  UUID: {}", info.uuid);
                        if let Some(path) = &info.file_path {
                            println!("  路徑: {}", path);
                        }
                        if let Some(name) = &info.file_name {
                            println!("  名稱: {}", name);
                        }
                        if let Some(dur) = info.duration {
                            println!("  時長: {:.2}s", dur);
                        }
                    }
                    Err(e) => println!("查詢失敗: {}", e),
                }
            }
            "5" => {
                println!("\n=== ▶ 播放影片 ===");
                print!("輸入影片 UUID (直接Enter從列表選擇): ");
                input.clear();
                std::io::stdin().read_line(&mut input)?;
                let uuid = input.trim();

                let video_path = if uuid.is_empty() {
                    println!("載入影片列表...");
                    match rt.block_on(client.list_videos()) {
                        Ok(videos) => {
                            if videos.is_empty() {
                                println!("沒有影片");
                                continue;
                            }
                            let entries: Vec<VideoEntry> = videos
                                .into_iter()
                                .map(|v| VideoEntry {
                                    uuid: v.uuid,
                                    file_name: v.file_name,
                                    file_path: v.file_path,
                                    duration: v.duration,
                                    width: v.width,
                                    height: v.height,
                                    thumbnail_dir: None,
                                })
                                .collect();

                            let mut selector = VideoSelector::new(entries);
                            match selector.run() {
                                Ok(Some(video)) => video.file_path,
                                Ok(None) => {
                                    println!("取消選擇");
                                    continue;
                                }
                                Err(e) => {
                                    println!("選擇錯誤: {}", e);
                                    continue;
                                }
                            }
                        }
                        Err(e) => {
                            println!("取得列表失敗: {}", e);
                            continue;
                        }
                    }
                } else {
                    match rt.block_on(client.lookup_video(uuid)) {
                        Ok(info) => {
                            if let Some(path) = info.file_path {
                                path
                            } else {
                                println!("找不到影片路徑");
                                continue;
                            }
                        }
                        Err(e) => {
                            println!("查詢失敗: {}", e);
                            continue;
                        }
                    }
                };

                let video_uuid = if let Ok(info) = rt.block_on(client.lookup_video(&video_path)) {
                    Some(info.uuid)
                } else {
                    None
                };

                println!("\n播放: {}", video_path);
                run_player(&video_path, video_uuid)?;
            }
            "q" | "Q" => {
                println!("\n再見!");
                break;
            }
            _ => {
                println!("無效選項，請重新選擇");
            }
        }
    }

    Ok(())
}
