import os
import json
import tempfile
import subprocess
from PIL import Image

class MetadataExtractor:
    def __init__(self):
        # Check for dependencies
        self._check_dependencies()
        
    def _check_dependencies(self):
        """Check if required command-line tools are available"""
        try:
            # Check for ffprobe (part of ffmpeg)
            subprocess.run(['ffprobe', '-version'], 
                          stdout=subprocess.PIPE, 
                          stderr=subprocess.PIPE)
        except FileNotFoundError:
            print("Warning: ffprobe not found. Install ffmpeg for better metadata extraction.")
    
    def extract(self, file_path):
        """Extract metadata from a music file"""
        if not os.path.exists(file_path):
            print(f"File not found: {file_path}")
            return None
        
        # Try to extract metadata using ffprobe
        metadata = self._extract_with_ffprobe(file_path)
        
        # If ffprobe failed, try to get basic info from file
        if not metadata:
            metadata = self._extract_basic_info(file_path)
        
        # Extract cover art if available
        cover_path = self._extract_cover_art(file_path)
        if cover_path:
            metadata['cover_path'] = cover_path
            
        return metadata
    
    def _extract_with_ffprobe(self, file_path):
        """Extract metadata using ffprobe"""
        try:
            cmd = [
                'ffprobe', 
                '-v', 'quiet',
                '-print_format', 'json',
                '-show_format',
                '-show_streams',
                file_path
            ]
            
            result = subprocess.run(cmd, 
                                   stdout=subprocess.PIPE, 
                                   stderr=subprocess.PIPE,
                                   text=True)
            
            if result.returncode != 0:
                return None
                
            data = json.loads(result.stdout)
            
            # Extract relevant metadata
            metadata = {}
            
            if 'format' in data:
                fmt = data['format']
                
                # Get duration in seconds
                if 'duration' in fmt:
                    metadata['duration'] = int(float(fmt['duration']))
                
                # Get bitrate
                if 'bit_rate' in fmt:
                    metadata['bitrate'] = int(int(fmt['bit_rate']) / 1000)  # Convert to kbps
                
                # Get tags
                if 'tags' in fmt:
                    tags = fmt['tags']
                    
                    # Map common tag names to our metadata keys
                    tag_mapping = {
                        'title': ['title', 'TITLE'],
                        'artist': ['artist', 'ARTIST', 'album_artist', 'ALBUM_ARTIST'],
                        'album': ['album', 'ALBUM'],
                        'genre': ['genre', 'GENRE'],
                        'year': ['date', 'year', 'YEAR', 'DATE'],
                        'track_number': ['track', 'TRACK']
                    }
                    
                    for meta_key, tag_keys in tag_mapping.items():
                        for tag_key in tag_keys:
                            if tag_key in tags:
                                value = tags[tag_key]
                                
                                # Convert track number (e.g. "1/12" to 1)
                                if meta_key == 'track_number' and '/' in value:
                                    value = value.split('/')[0]
                                
                                # Try to convert year to int
                                if meta_key == 'year' and value:
                                    try:
                                        # Extract first 4 digits if it's a date
                                        if len(value) > 4:
                                            value = value[:4]
                                        value = int(value)
                                    except ValueError:
                                        pass
                                
                                metadata[meta_key] = value
                                break
            
            return metadata
            
        except Exception as e:
            print(f"Error extracting metadata with ffprobe: {str(e)}")
            return None
    
    def _extract_basic_info(self, file_path):
        """Extract basic info from filename when metadata extraction fails"""
        filename = os.path.basename(file_path)
        name, _ = os.path.splitext(filename)
        
        # Try to parse "Artist - Title" format
        parts = name.split(' - ', 1)
        
        metadata = {
            'title': name,
            'file_path': file_path
        }
        
        if len(parts) == 2:
            metadata['artist'] = parts[0].strip()
            metadata['title'] = parts[1].strip()
        
        # Get file size and estimate duration (very rough)
        try:
            file_size = os.path.getsize(file_path) / (1024 * 1024)  # Size in MB
            # Rough estimate: 1MB ≈ 1 minute of music at moderate quality
            estimated_duration = int(file_size * 60)
            metadata['duration'] = estimated_duration
        except:
            pass
            
        return metadata
    
    def _extract_cover_art(self, file_path):
        """Extract cover art from audio file"""
        try:
            # Create a temporary directory for the cover art
            covers_dir = os.path.join('frontend', 'assets', 'covers')
            if not os.path.exists(covers_dir):
                os.makedirs(covers_dir)
            
            # Create a filename based on the audio file path
            file_hash = str(hash(file_path))
            cover_filename = f"cover_{file_hash}.jpg"
            cover_path = os.path.join(covers_dir, cover_filename)
            
            # Check if we already extracted this cover
            if os.path.exists(cover_path):
                return cover_path
                
            # Extract cover art using ffmpeg
            cmd = [
                'ffmpeg',
                '-i', file_path,
                '-an', '-vcodec', 'copy',
                cover_path
            ]
            
            result = subprocess.run(cmd, 
                                  stdout=subprocess.PIPE, 
                                  stderr=subprocess.PIPE)
            
            # If successful, return the path to the cover art
            if result.returncode == 0 and os.path.exists(cover_path):
                # Verify it's a valid image
                try:
                    with Image.open(cover_path) as img:
                        # If it's too small, it might not be a real cover
                        if img.width < 50 or img.height < 50:
                            os.remove(cover_path)
                            return None
                    return cover_path
                except:
                    # Not a valid image
                    if os.path.exists(cover_path):
                        os.remove(cover_path)
                    return None
            else:
                return None
                
        except Exception as e:
            print(f"Error extracting cover art: {str(e)}")
            return None
