import cv2
import os
import numpy as np
from pathlib import Path
from typing import Dict, List, Any
from PIL import Image
import tempfile
import shutil

class VideoAnalyzer:
    def __init__(self):
        print("🎬 Initializing video analyzer...")
        self.supported_formats = ['.mp4', '.avi', '.mov', '.mkv', '.webm', '.m4v']
        self.max_duration = 30  # seconds
        self.frames_per_second = 2  # Extract 2 frames per second
        print(f"   Supported formats: {self.supported_formats}")
        print(f"   Max duration: {self.max_duration} seconds")
        print("   ✅ Video analyzer ready")

    def analyze_video(self, video_path: str, output_dir: str = None) -> Dict[str, Any]:
        """
        Analyze video by extracting key frames
        """
        print(f"🎬 Analyzing video: {os.path.basename(video_path)}")

        if not self._is_supported_format(video_path):
            return {"error": "Unsupported video format"}

        try:
            # Open video file
            cap = cv2.VideoCapture(video_path)
            if not cap.isOpened():
                return {"error": "Could not open video file"}

            # Get video properties
            fps = cap.get(cv2.CAP_PROP_FPS)
            frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
            duration = frame_count / fps if fps > 0 else 0

            print(f"   Video properties: {duration:.1f}s, {fps:.1f} FPS, {frame_count} frames")

            # Check duration limit
            if duration > self.max_duration:
                cap.release()
                return {"error": f"Video too long ({duration:.1f}s). Max allowed: {self.max_duration}s"}

            # Extract frames
            frames_data = self._extract_frames(cap, fps, duration, output_dir)
            cap.release()

            analysis = {
                "file_path": video_path,
                "file_size_mb": os.path.getsize(video_path) / (1024 * 1024),
                "duration_seconds": duration,
                "fps": fps,
                "frame_count": frame_count,
                "extracted_frames": frames_data["frames"],
                "keyframes_analyzed": len(frames_data["frames"]),
                "frame_extraction_success": frames_data["success"]
            }

            print(f"   ✅ Video analysis complete - extracted {len(frames_data['frames'])} frames")
            return analysis

        except Exception as e:
            print(f"   ❌ Video analysis failed: {str(e)}")
            return {"error": f"Failed to analyze video: {str(e)}"}

    def _is_supported_format(self, video_path: str) -> bool:
        _, ext = os.path.splitext(video_path.lower())
        return ext in self.supported_formats

    def _extract_frames(self, cap: cv2.VideoCapture, fps: float, duration: float, output_dir: str = None) -> Dict[str, Any]:
        """
        Extract key frames from video at specified intervals
        """
        if output_dir is None:
            output_dir = tempfile.mkdtemp()
        else:
            os.makedirs(output_dir, exist_ok=True)

        frames = []
        frame_interval = max(1, int(fps / self.frames_per_second))  # Extract every N frames
        frame_num = 0
        extracted_count = 0

        print(f"   Extracting frames every {frame_interval} frames (≈{self.frames_per_second} per second)")

        while True:
            ret, frame = cap.read()
            if not ret:
                break

            # Extract frame at intervals + first and last frames
            if frame_num == 0 or frame_num % frame_interval == 0:
                try:
                    # Convert frame to RGB
                    frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)

                    # Create frame filename
                    timestamp = frame_num / fps if fps > 0 else extracted_count
                    frame_filename = f"frame_{extracted_count:03d}_t{timestamp:.1f}s.jpg"
                    frame_path = os.path.join(output_dir, frame_filename)

                    # Save frame as image
                    pil_image = Image.fromarray(frame_rgb)
                    pil_image.save(frame_path, 'JPEG', quality=85)

                    # Analyze frame quality
                    frame_quality = self._analyze_frame_quality(frame)

                    frame_data = {
                        "frame_number": frame_num,
                        "timestamp": timestamp,
                        "filename": frame_filename,
                        "path": frame_path,
                        "quality_score": frame_quality["sharpness"],
                        "brightness": frame_quality["brightness"]
                    }

                    frames.append(frame_data)
                    extracted_count += 1

                    if extracted_count % 5 == 0:
                        print(f"   Extracted {extracted_count} frames...")

                except Exception as e:
                    print(f"   ⚠️  Failed to save frame {frame_num}: {e}")

            frame_num += 1

            # Safety limit
            if extracted_count >= 60:  # Max 60 frames (30 seconds * 2 fps)
                print("   Reached frame extraction limit")
                break

        return {
            "frames": frames,
            "success": len(frames) > 0,
            "output_directory": output_dir
        }

    def _analyze_frame_quality(self, frame: np.ndarray) -> Dict[str, float]:
        """
        Quick quality analysis of a video frame
        """
        # Convert to grayscale
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

        # Calculate sharpness (Laplacian variance)
        sharpness = cv2.Laplacian(gray, cv2.CV_64F).var()

        # Calculate brightness
        brightness = np.mean(gray)

        return {
            "sharpness": float(sharpness),
            "brightness": float(brightness)
        }

    def get_best_frames(self, frames_data: List[Dict], max_frames: int = 10) -> List[Dict]:
        """
        Select the best quality frames for analysis
        """
        if len(frames_data) <= max_frames:
            return frames_data

        # Sort by quality score (sharpness) and select top frames
        sorted_frames = sorted(frames_data, key=lambda x: x.get('quality_score', 0), reverse=True)

        # Also ensure we get frames from different parts of the video
        selected = []
        selected.append(sorted_frames[0])  # Best quality frame

        # Add frames distributed across time
        if len(sorted_frames) > 1:
            selected.append(sorted_frames[-1] if sorted_frames[-1] != sorted_frames[0] else sorted_frames[1])

        # Fill remaining slots with best quality frames
        for frame in sorted_frames:
            if len(selected) >= max_frames:
                break
            if frame not in selected:
                selected.append(frame)

        return selected[:max_frames]

def is_video_file(filename: str) -> bool:
    """Helper function to check if a file is a supported video format"""
    _, ext = os.path.splitext(filename.lower())
    supported_formats = ['.mp4', '.avi', '.mov', '.mkv', '.webm', '.m4v']
    return ext in supported_formats