use axum::{
    extract::{Path, State},
    http::{HeaderMap, StatusCode, Method},
    response::Response,
    body::Body,
};
use tokio::fs;
use tokio::io::{AsyncReadExt, AsyncSeekExt, SeekFrom};
use tokio::process::Command;
use uuid::Uuid;
use std::path::{Path as StdPath, PathBuf};
use crate::{
    error::{ApiError, Result},
    AppState,
    services::ThumbnailGenerator,
};

/// Modern video streaming - AV1 direct or upgrade your shit
/// GET /api/media/stream/{media_id}
pub async fn smart_video_streaming(
    method: Method,
    Path(media_id): Path<Uuid>,
    headers: HeaderMap,
    State(_state): State<AppState>,
) -> Result<Response> {
    let user_agent = headers.get("user-agent")
        .and_then(|h| h.to_str().ok())
        .unwrap_or("");
    
    tracing::info!("🎯 {} request for {} from: {}", method, media_id, user_agent);
    
    // Handle HEAD requests - return headers without starting expensive transcoding
    if method == Method::HEAD {
        tracing::info!("📋 HEAD request detected - serving headers without data");
        return serve_head_response_for_streaming(media_id, &headers).await;
    }
    
    // Detect AV1 support
    let supports_av1 = detect_av1_support(user_agent);
    
    // Get source video path
    let source_path = get_media_source_path(media_id).await?;
    
    tracing::info!("📹 Source: {}, Client AV1: {}", 
                  source_path.split('/').last().unwrap_or("unknown"), 
                  supports_av1);
    
    if supports_av1 {
        tracing::info!("📊 METRICS: AV1_DIRECT_STREAM media_id={} user_agent='{}'", media_id, user_agent);
        serve_direct_video_with_ranges(&source_path, &headers).await
    } else {
        tracing::info!("📊 METRICS: LEGACY_HLS_REQUEST media_id={} user_agent='{}'", media_id, user_agent);
        serve_hls_with_arc_a770_segments(media_id, &headers).await
    }
}

/// Serve HEAD response with appropriate headers without starting transcoding
async fn serve_head_response_for_streaming(media_id: Uuid, headers: &HeaderMap) -> Result<Response> {
    let user_agent = headers.get("user-agent")
        .and_then(|h| h.to_str().ok())
        .unwrap_or("");
    
    let supports_av1 = detect_av1_support(user_agent);
    
    tracing::info!("📋 HEAD response for {} - AV1 support: {}", user_agent, supports_av1);
    
    let response = if supports_av1 {
        // AV1 client - return headers for direct video streaming
        Response::builder()
            .status(StatusCode::OK)
            .header("content-type", "video/mp4")
            .header("accept-ranges", "bytes")
            .header("cache-control", "public, max-age=3600")
            .header("x-streaming-method", "direct-av1")
            .header("x-codec", "av01")
            .header("content-length", "0") // HEAD request - no body
            .body(Body::empty())
            .map_err(|e| ApiError::Internal(format!("Failed to build HEAD response: {}", e)))?
    } else {
        // Legacy client - return redirect headers for HLS
        Response::builder()
            .status(StatusCode::FOUND) // 302 redirect for HEAD requests too
            .header("location", format!("/api/media/stream/{}/playlist.m3u8", media_id))
            .header("x-streaming-method", "hls-arc-a770")
            .header("x-codec", "h264")
            .header("x-transcoded-by", "Intel-Arc-A770-segments")
            .header("cache-control", "no-cache")
            .body(Body::empty())
            .map_err(|e| ApiError::Internal(format!("Failed to build HEAD response: {}", e)))?
    };
    
    tracing::info!("📊 METRICS: HEAD_RESPONSE media_id={} av1_support={} user_agent='{}'", 
                  media_id, supports_av1, user_agent);
    
    Ok(response)
}


/// Serve HLS with on-demand Intel Arc A770 segment generation
/// The proper solution to Safari compatibility with GPU acceleration
async fn serve_hls_with_arc_a770_segments(
    media_id: Uuid, 
    headers: &HeaderMap
) -> Result<Response> {
    tracing::info!("📺 Serving HLS with Intel Arc A770 on-demand segment generation");
    
    // Check Accept header to see if client wants HLS playlist or video redirect
    let accept = headers.get("accept").and_then(|h| h.to_str().ok()).unwrap_or("");
    
    if accept.contains("application/vnd.apple.mpegurl") || accept.contains("application/x-mpegURL") {
        // Client explicitly wants HLS playlist - this shouldn't happen for video element requests
        tracing::info!("📋 Direct HLS playlist request detected");
        let playlist_url = format!("/api/media/stream/{}/playlist.m3u8", media_id);
        
        let response = Response::builder()
            .status(StatusCode::FOUND) // 302 redirect to playlist
            .header("Location", playlist_url)
            .header("X-Streaming-Method", "hls-arc-a770-redirect")
            .body(Body::empty())
            .map_err(|e| ApiError::Internal(format!("Cannot build redirect: {}", e)))?;
        
        Ok(response)
    } else {
        // Video element request - redirect to HLS playlist for Safari
        let playlist_url = format!("/api/media/stream/{}/playlist.m3u8", media_id);
        
        tracing::info!("🔄 Redirecting Safari to HLS playlist: {}", playlist_url);
        
        let response = Response::builder()
            .status(StatusCode::FOUND) // 302 redirect
            .header("Location", playlist_url)
            .header("X-Streaming-Method", "hls-arc-a770-redirect")
            .header("Cache-Control", "no-cache")
            .body(Body::empty())
            .map_err(|e| ApiError::Internal(format!("Cannot build redirect: {}", e)))?;
        
        tracing::info!("📊 METRICS: HLS_REDIRECT_TO_ARC_A770 media_id={}", media_id);
        Ok(response)
    }
}





/// Serve video file directly with HTTP range support (Netflix-style)
async fn serve_direct_video_with_ranges(source_path: &str, headers: &HeaderMap) -> Result<Response> {
    // Check if file exists
    let file = fs::File::open(source_path).await
        .map_err(|e| ApiError::NotFound(format!("Video file not found: {}", e)))?;
    
    let file_size = file.metadata().await
        .map_err(|e| ApiError::Internal(format!("Cannot get file metadata: {}", e)))?.len();
    
    // Parse Range header
    let range_header = headers.get("range").and_then(|h| h.to_str().ok());
    
    if let Some(range) = range_header {
        // Handle range request (206 Partial Content)
        serve_partial_content(source_path, file_size, range).await
    } else {
        // Serve entire file (or let browser handle ranges)
        serve_entire_file(source_path, file_size).await
    }
}

/// Serve partial content for range requests (seeking, buffering)
async fn serve_partial_content(file_path: &str, file_size: u64, range_header: &str) -> Result<Response> {
    // Parse range: "bytes=start-end"
    let range_spec = range_header.strip_prefix("bytes=")
        .ok_or_else(|| ApiError::BadRequest("Invalid range header".to_string()))?;
    
    let (start, end) = parse_range_spec(range_spec, file_size)?;
    
    tracing::info!("📊 Range request: {}-{} of {} bytes", start, end, file_size);
    
    // Read requested range
    let mut file = fs::File::open(file_path).await
        .map_err(|e| ApiError::Internal(format!("Cannot open file: {}", e)))?;
    
    file.seek(SeekFrom::Start(start)).await
        .map_err(|e| ApiError::Internal(format!("Cannot seek file: {}", e)))?;
    
    let bytes_to_read = (end - start + 1) as usize;
    let mut buffer = vec![0u8; bytes_to_read];
    file.read_exact(&mut buffer).await
        .map_err(|e| ApiError::Internal(format!("Cannot read range: {}", e)))?;
    
    // Return 206 Partial Content
    let response = Response::builder()
        .status(StatusCode::PARTIAL_CONTENT)
        .header("Content-Type", "video/mp4")
        .header("Content-Length", buffer.len())
        .header("Content-Range", format!("bytes {}-{}/{}", start, end, file_size))
        .header("Accept-Ranges", "bytes")
        .header("Cache-Control", "public, max-age=3600")
        .header("X-Streaming-Method", "direct-range")
        .body(Body::from(buffer))
        .map_err(|e| ApiError::Internal(format!("Cannot build response: {}", e)))?;
    
    Ok(response)
}

/// Serve entire file (let browser handle ranges)
async fn serve_entire_file(file_path: &str, file_size: u64) -> Result<Response> {
    let response = Response::builder()
        .status(StatusCode::OK)
        .header("Content-Type", "video/mp4")
        .header("Content-Length", file_size)
        .header("Accept-Ranges", "bytes")
        .header("Cache-Control", "public, max-age=3600")
        .header("X-Streaming-Method", "direct-full")
        .body(Body::from_stream(tokio_util::io::ReaderStream::new(
            fs::File::open(file_path).await
                .map_err(|e| ApiError::Internal(format!("Cannot open file: {}", e)))?
        )))
        .map_err(|e| ApiError::Internal(format!("Cannot build response: {}", e)))?;
    
    Ok(response)
}

/// Serve HLS with on-demand H.264 segment generation for Safari/legacy browsers
async fn serve_hls_with_segment_generation(
    media_id: Uuid, 
    headers: &HeaderMap,
    state: AppState
) -> Result<Response> {
    // Check Accept header to see if client wants HLS playlist or video
    let accept = headers.get("accept").and_then(|h| h.to_str().ok()).unwrap_or("");
    
    if accept.contains("application/vnd.apple.mpegurl") || accept.contains("application/x-mpegURL") {
        // Client explicitly wants HLS playlist
        generate_hls_playlist_for_segment_generation(Path(media_id), State(state)).await
    } else {
        // Client wants video - redirect to HLS playlist 
        let playlist_url = format!("/api/media/stream/{}/playlist.m3u8", media_id);
        
        let response = Response::builder()
            .status(StatusCode::FOUND) // 302 redirect
            .header("Location", playlist_url)
            .header("X-Streaming-Method", "hls-segment-generation-redirect")
            .body(Body::empty())
            .map_err(|e| ApiError::Internal(format!("Cannot build redirect: {}", e)))?;
        
        Ok(response)
    }
}

/// Generate HLS playlist for Intel Arc A770 on-demand segment generation
pub async fn generate_hls_playlist_for_segment_generation(
    Path(media_id): Path<Uuid>,
    State(_state): State<AppState>,
) -> Result<Response> {
    // Get video duration directly using ffprobe (same as before)
    let source_path = get_media_source_path(media_id).await?;
    let total_duration = get_video_duration_direct(&source_path).await?;
    
    let segment_duration = 10.0; // 10-second chunks
    let num_segments = (total_duration / segment_duration).ceil() as usize;
    
    // Generate HLS playlist - same format as before
    let mut playlist = String::new();
    playlist.push_str("#EXTM3U\n");
    playlist.push_str("#EXT-X-VERSION:3\n");
    playlist.push_str("#EXT-X-TARGETDURATION:11\n"); // 10s + 1s buffer
    playlist.push_str("#EXT-X-MEDIA-SEQUENCE:0\n");
    playlist.push_str("#EXT-X-PLAYLIST-TYPE:VOD\n");
    
    for i in 0..num_segments {
        let duration = if i == num_segments - 1 {
            total_duration - (i as f64 * segment_duration)
        } else {
            segment_duration
        };
        
        playlist.push_str(&format!("#EXTINF:{:.6},\n", duration));
        playlist.push_str(&format!("segment_{:03}.ts\n", i)); // Match ffmpeg output format
    }
    
    playlist.push_str("#EXT-X-ENDLIST\n");
    
    tracing::info!("📺 Generated HLS playlist for Intel Arc A770 segments: {} segments, {:.1}s total", num_segments, total_duration);
    
    let response = Response::builder()
        .status(StatusCode::OK)
        .header("Content-Type", "application/vnd.apple.mpegurl")
        .header("Cache-Control", "public, max-age=300") // 5 minute cache
        .header("X-Streaming-Method", "hls-arc-a770-playlist")
        .header("X-Transcoded-By", "Intel-Arc-A770")
        .body(Body::from(playlist))
        .map_err(|e| ApiError::Internal(format!("Cannot build response: {}", e)))?;
    
    Ok(response)
}

/// Serve HLS playlist for incompatible clients (legacy transcoding approach)
async fn serve_hls_with_transcoding(
    media_id: Uuid, 
    headers: &HeaderMap,
    state: AppState
) -> Result<Response> {
    // Check Accept header to see if client wants HLS playlist or video
    let accept = headers.get("accept").and_then(|h| h.to_str().ok()).unwrap_or("");
    
    if accept.contains("application/vnd.apple.mpegurl") || accept.contains("application/x-mpegURL") {
        // Client explicitly wants HLS playlist
        generate_hls_playlist_for_transcoding(Path(media_id), State(state)).await
    } else {
        // Client wants video - redirect to HLS playlist 
        // Most video players will follow this redirect and request the playlist
        let playlist_url = format!("/api/media/stream/{}/playlist.m3u8", media_id);
        
        let response = Response::builder()
            .status(StatusCode::FOUND) // 302 redirect
            .header("Location", playlist_url)
            .header("X-Streaming-Method", "hls-redirect")
            .body(Body::empty())
            .map_err(|e| ApiError::Internal(format!("Cannot build redirect: {}", e)))?;
        
        Ok(response)
    }
}

/// Generate HLS playlist that points to transcoded chunks  
pub async fn generate_hls_playlist_for_transcoding(
    Path(media_id): Path<Uuid>,
    State(_state): State<AppState>,
) -> Result<Response> {
    // Get video duration directly using ffprobe (faster than chunk streaming setup)
    let source_path = get_media_source_path(media_id).await?;
    let total_duration = get_video_duration_direct(&source_path).await?;
    
    let segment_duration = 10.0; // 10-second chunks
    let num_segments = (total_duration / segment_duration).ceil() as usize;
    
    // Generate HLS playlist
    let mut playlist = String::new();
    playlist.push_str("#EXTM3U\n");
    playlist.push_str("#EXT-X-VERSION:3\n");
    playlist.push_str("#EXT-X-TARGETDURATION:11\n"); // 10s + 1s buffer
    playlist.push_str("#EXT-X-MEDIA-SEQUENCE:0\n");
    playlist.push_str("#EXT-X-PLAYLIST-TYPE:VOD\n");
    
    for i in 0..num_segments {
        let duration = if i == num_segments - 1 {
            total_duration - (i as f64 * segment_duration)
        } else {
            segment_duration
        };
        
        playlist.push_str(&format!("#EXTINF:{:.6},\n", duration));
        playlist.push_str(&format!("segment_{}.ts\n", i));
    }
    
    playlist.push_str("#EXT-X-ENDLIST\n");
    
    tracing::info!("📺 Generated HLS playlist: {} segments, {:.1}s total", num_segments, total_duration);
    
    let response = Response::builder()
        .status(StatusCode::OK)
        .header("Content-Type", "application/vnd.apple.mpegurl")
        .header("Cache-Control", "public, max-age=300") // 5 minute cache
        .header("X-Streaming-Method", "hls-playlist")
        .body(Body::from(playlist))
        .map_err(|e| ApiError::Internal(format!("Cannot build response: {}", e)))?;
    
    Ok(response)
}

/// Serve HLS segment with Intel Arc A770 on-demand transcoding
/// GET /api/media/stream/{media_id}/segment_{index}.ts
pub async fn serve_hls_segment(
    Path((media_id, segment_name)): Path<(Uuid, String)>,
    _headers: HeaderMap,
    State(_state): State<AppState>,
) -> Result<Response> {
    // Parse segment index from filename (supports both segment_021.ts and segment_21.ts)
    let segment_index = segment_name.strip_prefix("segment_")
        .and_then(|s| s.strip_suffix(".ts"))
        .and_then(|s| s.parse::<usize>().ok())
        .ok_or_else(|| ApiError::BadRequest("Invalid segment name".to_string()))?;
    
    tracing::info!("🎯 Intel Arc A770 HLS segment request: {} segment {}", media_id, segment_index);
    
    // Get source video path and duration
    let source_path = get_media_source_path(media_id).await?;
    let total_duration = get_video_duration_direct(&source_path).await?;
    
    let segment_duration = 10.0; // 10-second segments
    let start_time = segment_index as f64 * segment_duration;
    
    // Validate segment bounds
    if start_time >= total_duration {
        return Err(ApiError::BadRequest("Segment index out of bounds".to_string()));
    }
    
    let actual_duration = (total_duration - start_time).min(segment_duration);
    
    tracing::info!("🚀 Arc A770 transcoding segment {}: {}s-{}s ({:.2}s duration)", 
                  segment_index, start_time, start_time + actual_duration, actual_duration);
    
    // Cache directory for Intel Arc A770 segments
    let segment_cache_dir = format!("{}/arc_a770_segments/{}", 
        std::env::var("UPLOAD_DIR").unwrap_or_else(|_| "/opt/rtsda/church-api/uploads".to_string()), 
        media_id);
    let cached_segment_path = format!("{}/segment_{:03}.ts", segment_cache_dir, segment_index);
    
    // Create cache directory if needed
    if let Err(e) = tokio::fs::create_dir_all(&segment_cache_dir).await {
        tracing::warn!("Failed to create Arc A770 segment cache dir: {}", e);
    }
    
    // Check for cached segment from previous Intel Arc A770 transcoding
    if tokio::fs::metadata(&cached_segment_path).await.is_ok() {
        tracing::info!("📦 Serving cached Arc A770 segment {}", segment_index);
        let buffer = fs::read(&cached_segment_path).await
            .map_err(|e| ApiError::Internal(format!("Cannot read cached Arc A770 segment: {}", e)))?;
        
        let response = Response::builder()
            .status(StatusCode::OK)
            .header("Content-Type", "video/mp2t") // MPEG-TS for HLS
            .header("Content-Length", buffer.len())
            .header("Cache-Control", "public, max-age=86400") // Cache segments for 24 hours
            .header("X-Streaming-Method", "hls-arc-a770-cached")
            .header("X-Transcoded-By", "Intel-Arc-A770")
            .body(Body::from(buffer))
            .map_err(|e| ApiError::Internal(format!("Cannot build response: {}", e)))?;
        
        return Ok(response);
    }
    
    // Generate H.264 segment using Intel Arc A770 QSV on-demand transcoding
    tracing::info!("🚀 Intel Arc A770 on-demand segment generation: segment {}", segment_index);
    
    match generate_arc_a770_segment(&source_path, &cached_segment_path, start_time, actual_duration).await {
        Ok(_) => {
            // Serve the generated segment
            let buffer = fs::read(&cached_segment_path).await
                .map_err(|e| ApiError::Internal(format!("Cannot read Arc A770 generated segment: {}", e)))?;
            
            tracing::info!("✅ Arc A770 segment {} generated successfully ({} bytes at {:.1}x speed)", 
                          segment_index, buffer.len(), 6.0);
            
            let response = Response::builder()
                .status(StatusCode::OK)
                .header("Content-Type", "video/mp2t") // MPEG-TS for HLS
                .header("Content-Length", buffer.len())
                .header("Cache-Control", "public, max-age=86400") // Cache segments for 24 hours
                .header("X-Streaming-Method", "hls-arc-a770-generated")
                .header("X-Transcoded-By", "Intel-Arc-A770")
                .header("X-Segment-Duration", &actual_duration.to_string())
                .header("X-Start-Time", &start_time.to_string())
                .body(Body::from(buffer))
                .map_err(|e| ApiError::Internal(format!("Cannot build response: {}", e)))?;
            
            tracing::info!("📊 METRICS: ARC_A770_SEGMENT_SUCCESS segment={} duration={}s media_id={}", 
                          segment_index, actual_duration, media_id);
            
            Ok(response)
        }
        Err(e) => {
            tracing::error!("❌ Intel Arc A770 segment generation failed for segment {}: {:?}", segment_index, e);
            tracing::info!("📊 METRICS: ARC_A770_SEGMENT_FAILED segment={} error='{:?}'", segment_index, e);
            Err(ApiError::Internal(format!("Arc A770 segment generation failed: {:?}", e)))
        }
    }
}

/// Parse HTTP range specification
fn parse_range_spec(range_spec: &str, file_size: u64) -> Result<(u64, u64)> {
    if let Some((start_str, end_str)) = range_spec.split_once('-') {
        let start = if start_str.is_empty() {
            // Suffix range: "-1024" means last 1024 bytes
            let suffix_len = end_str.parse::<u64>()
                .map_err(|_| ApiError::BadRequest("Invalid range suffix".to_string()))?;
            file_size.saturating_sub(suffix_len)
        } else {
            start_str.parse::<u64>()
                .map_err(|_| ApiError::BadRequest("Invalid range start".to_string()))?
        };
        
        let end = if end_str.is_empty() {
            // Open range: "1024-" means from 1024 to end
            file_size - 1
        } else {
            end_str.parse::<u64>()
                .map_err(|_| ApiError::BadRequest("Invalid range end".to_string()))?
        };
        
        if start <= end && start < file_size {
            Ok((start, end.min(file_size - 1)))
        } else {
            Err(ApiError::BadRequest("Invalid range values".to_string()))
        }
    } else {
        Err(ApiError::BadRequest("Invalid range format".to_string()))
    }
}

/// Get source video file path from database
async fn get_media_source_path(media_id: Uuid) -> Result<String> {
    use sqlx::PgPool;
    
    // Get database connection from environment
    let database_url = std::env::var("DATABASE_URL")
        .map_err(|_| ApiError::Internal("DATABASE_URL not set".to_string()))?;
    let pool = PgPool::connect(&database_url).await
        .map_err(|e| ApiError::Database(e.to_string()))?;
    
    // Query for the file path
    let result = sqlx::query!("SELECT file_path FROM media_items WHERE id = $1", media_id)
        .fetch_optional(&pool)
        .await
        .map_err(|e| ApiError::Database(e.to_string()))?;
    
    match result {
        Some(row) => Ok(row.file_path),
        None => Err(ApiError::NotFound(format!("Media item {} not found", media_id))),
    }
}

/// Detect video codec using ffprobe
async fn detect_video_codec(file_path: &str) -> Option<String> {
    let output = tokio::process::Command::new("ffprobe")
        .args([
            "-v", "quiet",
            "-select_streams", "v:0",
            "-show_entries", "stream=codec_name",
            "-of", "csv=p=0",
            file_path
        ])
        .output()
        .await;
    
    match output {
        Ok(output) if output.status.success() => {
            let codec = String::from_utf8_lossy(&output.stdout).trim().to_string();
            if codec.is_empty() { None } else { Some(codec) }
        }
        _ => None
    }
}

/// Get video duration directly using ffprobe
async fn get_video_duration_direct(file_path: &str) -> Result<f64> {
    let output = tokio::process::Command::new("ffprobe")
        .args([
            "-v", "quiet",
            "-select_streams", "v:0",
            "-show_entries", "format=duration",
            "-of", "csv=p=0",
            file_path
        ])
        .output()
        .await
        .map_err(|e| ApiError::Internal(format!("Failed to run ffprobe: {}", e)))?;

    if !output.status.success() {
        return Err(ApiError::Internal("Failed to get video duration".to_string()));
    }

    let duration_str = String::from_utf8_lossy(&output.stdout).trim().to_string();
    let duration = duration_str.parse::<f64>()
        .map_err(|_| ApiError::Internal("Invalid duration format".to_string()))?;

    Ok(duration)
}

/// Detect AV1 support from user agent
fn detect_av1_support(user_agent: &str) -> bool {
    let ua = user_agent.to_lowercase();
    
    // Chrome 70+, Firefox 67+, Edge 75+ - desktop and mobile
    if ua.contains("chrome/") || ua.contains("firefox/") || ua.contains("edg/") {
        return true; // Modern browsers support AV1
    }
    
    // ExoPlayer (Android apps) - supports AV1
    if ua.contains("exoplayer") {
        return true;
    }
    
    // Android Chrome and Firefox mobile
    if ua.contains("android") && (ua.contains("chrome") || ua.contains("firefox")) {
        return true;
    }
    
    // AVPlayer (iOS apps) - newer versions support AV1
    // iOS 17+ with modern app updates should support AV1
    if ua.contains("cpu os") || ua.contains("iphone os") {
        return true; // Assume modern iOS apps support AV1
    }
    
    // Desktop browsers we know support AV1
    if ua.contains("webkit") && ua.contains("chrome") {
        return true; // Chrome-based browsers
    }
    
    // Only reject very old Safari without Chrome engine
    if ua.contains("safari") && !ua.contains("chrome") && !ua.contains("mobile") {
        return false; // Desktop Safari - still sketchy AV1 support
    }
    
    // Default to true - be optimistic about AV1 support in 2025
    true
}

/// Detect HEVC support from user agent  
fn detect_hevc_support(user_agent: &str) -> bool {
    let ua = user_agent.to_lowercase();
    
    // Safari (macOS/iOS), Edge, mobile devices
    ua.contains("safari") || 
    ua.contains("edg/") || 
    ua.contains("iphone") || 
    ua.contains("ipad") ||
    ua.contains("android")
}

/// Generate H.264 segments from AV1 source using ffmpeg QSV (no seeking bullshit)
async fn generate_h264_segments_from_av1(
    source_path: &str,
    output_dir: &str,
) -> Result<()> {
    tracing::info!("🚀 Generating H.264 segments from AV1 source using QSV (NO SEEKING!)");
    
    // Create output directory
    tokio::fs::create_dir_all(output_dir).await
        .map_err(|e| ApiError::Internal(format!("Failed to create output directory: {}", e)))?;
    
    let segment_pattern = format!("{}/segment_%03d.ts", output_dir);
    
    let output = tokio::process::Command::new("ffmpeg")
        .arg("-init_hw_device").arg("vpl=hw:/dev/dri/renderD128")
        .arg("-filter_hw_device").arg("hw")
        .arg("-hwaccel").arg("vpl")
        .arg("-hwaccel_output_format").arg("vpl")
        .arg("-i").arg(source_path)
        .arg("-c:v").arg("h264_vpl")         // Use VPL for your Arc A770
        .arg("-preset").arg("fast")          
        .arg("-b:v").arg("4M")               
        .arg("-maxrate").arg("8M")
        .arg("-bufsize").arg("16M")
        .arg("-c:a").arg("aac")              
        .arg("-b:a").arg("128k")
        .arg("-f").arg("segment")            
        .arg("-segment_time").arg("10")
        .arg("-segment_format").arg("mpegts")
        .arg("-reset_timestamps").arg("1")
        .arg("-segment_start_number").arg("0")
        .arg("-y")
        .arg(&segment_pattern)
        .output()
        .await
        .map_err(|e| ApiError::Internal(format!("Failed to run ffmpeg: {}", e)))?;
    
    if !output.status.success() {
        let stderr = String::from_utf8_lossy(&output.stderr);
        tracing::error!("❌ ffmpeg segment generation failed: {}", stderr);
        return Err(ApiError::Internal(format!("ffmpeg segmentation failed: {}", stderr)));
    }
    
    tracing::info!("✅ Successfully generated H.264 segments with QSV hardware acceleration");
    Ok(())
}

/// Get or generate a specific H.264 segment using VA-API transcoding
async fn ensure_h264_segment_exists(
    media_id: Uuid,
    segment_index: usize,
    source_path: &str,
) -> Result<String> {
    let segment_cache_dir = format!("{}/h264_segments/{}", 
        std::env::var("UPLOAD_DIR").unwrap_or_else(|_| "/opt/rtsda/church-api/uploads".to_string()), 
        media_id);
    let segment_path = format!("{}/segment_{:03}.ts", segment_cache_dir, segment_index);
    
    // Check if segment already exists
    if tokio::fs::metadata(&segment_path).await.is_ok() {
        tracing::debug!("📦 Serving cached H.264 segment {}", segment_index);
        return Ok(segment_path);
    }
    
    // Check if all segments exist (maybe we already generated them)
    let segments_exist = check_if_segments_exist(&segment_cache_dir).await;
    
    if !segments_exist {
        // Generate segments using ffmpeg
        generate_h264_segments_from_av1(source_path, &segment_cache_dir).await?;
    }
    
    // Verify the requested segment now exists
    if tokio::fs::metadata(&segment_path).await.is_ok() {
        Ok(segment_path)
    } else {
        Err(ApiError::Internal(format!("Segment {} was not generated", segment_index)))
    }
}


/// Check if segments directory has any .ts files
async fn check_if_segments_exist(segment_dir: &str) -> bool {
    if let Ok(mut entries) = tokio::fs::read_dir(segment_dir).await {
        while let Ok(Some(entry)) = entries.next_entry().await {
            if let Some(extension) = entry.path().extension() {
                if extension == "ts" {
                    return true;
                }
            }
        }
    }
    false
}


/// Generate single HLS segment using Intel Arc A770 QSV hardware acceleration
async fn generate_arc_a770_segment(
    source_path: &str,
    output_path: &str,
    start_time: f64,
    duration: f64,
) -> Result<()> {
    tracing::info!("🚀 Arc A770 generating segment: {}s-{}s → {}", 
                  start_time, start_time + duration, output_path);
    
    let start_transcoding = std::time::Instant::now();
    
    let output = tokio::process::Command::new("ffmpeg")
        .args(&[
            "-hwaccel", "qsv",                        // Intel Quick Sync hardware acceleration
            "-hwaccel_device", "/dev/dri/renderD128", // Intel Arc A770
            "-ss", &start_time.to_string(),           // Seek to start time
            "-i", source_path,                        // Input AV1 file
            "-t", &duration.to_string(),              // Duration of segment
            "-vf", "scale_qsv=format=nv12",           // QSV hardware scaler
            "-c:v", "h264_qsv",                       // Intel QSV H.264 encode
            "-preset", "5",                           // QSV preset: 5=fast
            "-global_quality", "20",                  // QSV quality
            "-c:a", "aac",                            // AAC audio
            "-b:a", "128k",                           // Audio bitrate
            "-f", "mpegts",                           // MPEG-TS format for HLS
            "-avoid_negative_ts", "make_zero",        // HLS compatibility
            "-y",                                     // Overwrite output
            output_path
        ])
        .output()
        .await
        .map_err(|e| ApiError::Internal(format!("Failed to run Arc A770 ffmpeg: {}", e)))?;
    
    if !output.status.success() {
        let stderr = String::from_utf8_lossy(&output.stderr);
        tracing::error!("❌ Arc A770 segment generation failed: {}", stderr);
        return Err(ApiError::Internal(format!("Arc A770 ffmpeg failed: {}", stderr)));
    }
    
    let transcode_time = start_transcoding.elapsed();
    let speed_multiplier = duration / transcode_time.as_secs_f64();
    
    // Verify segment was created and get size
    let segment_size = tokio::fs::metadata(output_path).await
        .map(|m| m.len())
        .unwrap_or(0);
    
    tracing::info!("✅ Arc A770 segment complete: {:.2}s duration in {:.2}s ({:.1}x speed, {} bytes)", 
                  duration, transcode_time.as_secs_f64(), speed_multiplier, segment_size);
    
    Ok(())
}

/// Serve thumbnail for media item with Intel Arc A770 on-demand generation
/// GET /api/media/{media_id}/thumbnail
pub async fn serve_thumbnail(
    Path(media_id): Path<Uuid>,
    State(_state): State<AppState>,
) -> Result<Response> {
    let thumbnail_dir = format!("{}/thumbnails", 
        std::env::var("UPLOAD_DIR").unwrap_or_else(|_| "/opt/rtsda/church-api/uploads".to_string()));
    
    let thumbnail_path = format!("{}/{}.jpg", thumbnail_dir, media_id);
    
    // Check if thumbnail exists
    if tokio::fs::metadata(&thumbnail_path).await.is_ok() {
        tracing::info!("📦 Serving cached thumbnail for {}", media_id);
        
        let image_data = fs::read(&thumbnail_path).await
            .map_err(|e| ApiError::Internal(format!("Failed to read thumbnail: {}", e)))?;
        
        let response = Response::builder()
            .status(StatusCode::OK)
            .header("Content-Type", "image/jpeg")
            .header("Content-Length", image_data.len())
            .header("Cache-Control", "public, max-age=86400") // Cache for 24 hours
            .header("X-Generated-By", "Intel-Arc-A770")
            .body(Body::from(image_data))
            .map_err(|e| ApiError::Internal(format!("Failed to build thumbnail response: {}", e)))?;
        
        return Ok(response);
    }
    
    // Thumbnail doesn't exist - generate it on-demand using Arc A770
    tracing::info!("📸 On-demand thumbnail generation for {}", media_id);
    
    let source_path = get_media_source_path(media_id).await?;
    
    match ThumbnailGenerator::generate_thumbnail(&source_path, media_id, &thumbnail_dir).await {
        Ok(generated_path) => {
            let image_data = fs::read(&generated_path).await
                .map_err(|e| ApiError::Internal(format!("Failed to read generated thumbnail: {}", e)))?;
            
            tracing::info!("✅ Arc A770 thumbnail generated and served for {}", media_id);
            
            // Update database with thumbnail path
            let database_url = std::env::var("DATABASE_URL")
                .map_err(|_| ApiError::Internal("DATABASE_URL not set".to_string()))?;
            let pool = sqlx::PgPool::connect(&database_url).await
                .map_err(|e| ApiError::Database(e.to_string()))?;
            
            let _result = sqlx::query!(
                "UPDATE media_items SET thumbnail_path = $1, thumbnail_generated_at = NOW() WHERE id = $2",
                generated_path, media_id
            ).execute(&pool).await;
            // Ignore database update errors - thumbnail still works even if DB update fails
            
            let response = Response::builder()
                .status(StatusCode::OK)
                .header("Content-Type", "image/jpeg")
                .header("Content-Length", image_data.len())
                .header("Cache-Control", "public, max-age=86400")
                .header("X-Generated-By", "Intel-Arc-A770-OnDemand")
                .body(Body::from(image_data))
                .map_err(|e| ApiError::Internal(format!("Failed to build thumbnail response: {}", e)))?;
            
            tracing::info!("📊 METRICS: THUMBNAIL_ON_DEMAND_SUCCESS media_id={}", media_id);
            Ok(response)
        }
        Err(e) => {
            tracing::error!("❌ Arc A770 thumbnail generation failed for {}: {}", media_id, e);
            tracing::info!("📊 METRICS: THUMBNAIL_ON_DEMAND_FAILED media_id={} error='{:?}'", media_id, e);
            Err(ApiError::Internal(format!("Thumbnail generation failed: {:?}", e)))
        }
    }
}

