"""ID3 tagging service using mutagen"""
import os
import logging
from mutagen.mp4 import MP4, MP4Cover
from mutagen.id3 import ID3, APIC, TIT2, TPE1, TALB, TDRC, TRCK, TCON, TXXX
from mutagen.flac import FLAC, Picture
from typing import Optional, Dict, Any

logger = logging.getLogger(__name__)


class ID3TagService:
    """Service for reading and writing ID3 tags"""
    
    @staticmethod
    def read_tags(file_path: str) -> Dict[str, Any]:
        """
        Read ID3 tags from audio file
        
        Args:
            file_path: Path to audio file
            
        Returns:
            Dictionary with tag information
        """
        try:
            if not os.path.exists(file_path):
                logger.error(f"File not found: {file_path}")
                return {}
            
            ext = os.path.splitext(file_path)[1].lower()
            tags = {}
            
            if ext == '.m4a' or ext == '.mp4':
                audio = MP4(file_path)
                tags = {
                    'title': audio.get('\xa9nam', [''])[0],
                    'artist': audio.get('\xa9ART', [''])[0],
                    'album': audio.get('\xa9alb', [''])[0],
                    'album_artist': audio.get('aART', [''])[0],
                    'year': audio.get('\xa9day', [''])[0],
                    'genre': audio.get('\xa9gen', [''])[0],
                    'track_number': audio.get('trkn', [(0, 0)])[0][0],
                    'disc_number': audio.get('disk', [(0, 0)])[0][0],
                    'duration': audio.info.length if audio.info else 0,
                    'bitrate': audio.info.bitrate if audio.info else 0,
                    'has_cover': 'covr' in audio,
                }
            
            elif ext == '.mp3':
                audio = ID3(file_path)
                tags = {
                    'title': str(audio.get('TIT2', '')),
                    'artist': str(audio.get('TPE1', '')),
                    'album': str(audio.get('TALB', '')),
                    'album_artist': str(audio.get('TPE2', '')),
                    'year': str(audio.get('TDRC', '')),
                    'genre': str(audio.get('TCON', '')),
                    'track_number': str(audio.get('TRCK', '')).split('/')[0] if audio.get('TRCK') else '',
                    'disc_number': str(audio.get('TPOS', '')).split('/')[0] if audio.get('TPOS') else '',
                    'has_cover': 'APIC:' in audio or any(k.startswith('APIC') for k in audio.keys()),
                }
            
            elif ext == '.flac':
                audio = FLAC(file_path)
                tags = {
                    'title': audio.get('title', [''])[0],
                    'artist': audio.get('artist', [''])[0],
                    'album': audio.get('album', [''])[0],
                    'album_artist': audio.get('albumartist', [''])[0],
                    'year': audio.get('date', [''])[0],
                    'genre': audio.get('genre', [''])[0],
                    'track_number': audio.get('tracknumber', [''])[0],
                    'disc_number': audio.get('discnumber', [''])[0],
                    'duration': audio.info.length if audio.info else 0,
                    'has_cover': len(audio.pictures) > 0,
                }
            
            return tags
            
        except Exception as e:
            logger.error(f"Error reading tags from {file_path}: {e}")
            return {}
    
    @staticmethod
    def write_tags(file_path: str, tags: Dict[str, Any]) -> bool:
        """
        Write ID3 tags to audio file
        
        Args:
            file_path: Path to audio file
            tags: Dictionary with tag information
            
        Returns:
            True if successful, False otherwise
        """
        try:
            if not os.path.exists(file_path):
                logger.error(f"File not found: {file_path}")
                return False
            
            ext = os.path.splitext(file_path)[1].lower()
            
            if ext == '.m4a' or ext == '.mp4':
                audio = MP4(file_path)
                
                if 'title' in tags:
                    audio['\xa9nam'] = tags['title']
                if 'artist' in tags:
                    audio['\xa9ART'] = tags['artist']
                if 'album' in tags:
                    audio['\xa9alb'] = tags['album']
                if 'album_artist' in tags:
                    audio['aART'] = tags['album_artist']
                if 'year' in tags:
                    audio['\xa9day'] = str(tags['year'])
                if 'genre' in tags:
                    audio['\xa9gen'] = tags['genre']
                if 'track_number' in tags:
                    audio['trkn'] = [(int(tags['track_number']), 0)]
                if 'disc_number' in tags:
                    audio['disk'] = [(int(tags['disc_number']), 0)]
                
                audio.save()
            
            elif ext == '.mp3':
                try:
                    audio = ID3(file_path)
                except:
                    audio = ID3()
                
                if 'title' in tags:
                    audio['TIT2'] = TIT2(encoding=3, text=tags['title'])
                if 'artist' in tags:
                    audio['TPE1'] = TPE1(encoding=3, text=tags['artist'])
                if 'album' in tags:
                    audio['TALB'] = TALB(encoding=3, text=tags['album'])
                if 'year' in tags:
                    audio['TDRC'] = TDRC(encoding=3, text=str(tags['year']))
                if 'genre' in tags:
                    audio['TCON'] = TCON(encoding=3, text=tags['genre'])
                if 'track_number' in tags:
                    audio['TRCK'] = TRCK(encoding=3, text=str(tags['track_number']))
                
                audio.save(file_path)
            
            elif ext == '.flac':
                audio = FLAC(file_path)
                
                if 'title' in tags:
                    audio['title'] = tags['title']
                if 'artist' in tags:
                    audio['artist'] = tags['artist']
                if 'album' in tags:
                    audio['album'] = tags['album']
                if 'album_artist' in tags:
                    audio['albumartist'] = tags['album_artist']
                if 'year' in tags:
                    audio['date'] = str(tags['year'])
                if 'genre' in tags:
                    audio['genre'] = tags['genre']
                if 'track_number' in tags:
                    audio['tracknumber'] = str(tags['track_number'])
                if 'disc_number' in tags:
                    audio['discnumber'] = str(tags['disc_number'])
                
                audio.save()
            
            logger.info(f"Successfully wrote tags to {file_path}")
            return True
            
        except Exception as e:
            logger.error(f"Error writing tags to {file_path}: {e}")
            return False
    
    @staticmethod
    def embed_cover_art(file_path: str, image_data: bytes, mime_type: str = 'image/jpeg') -> bool:
        """
        Embed cover art into audio file
        
        Args:
            file_path: Path to audio file
            image_data: Image binary data
            mime_type: MIME type of image
            
        Returns:
            True if successful, False otherwise
        """
        try:
            if not os.path.exists(file_path):
                logger.error(f"File not found: {file_path}")
                return False
            
            ext = os.path.splitext(file_path)[1].lower()
            
            if ext == '.m4a' or ext == '.mp4':
                audio = MP4(file_path)
                
                if mime_type == 'image/png':
                    cover_format = MP4Cover.FORMAT_PNG
                else:
                    cover_format = MP4Cover.FORMAT_JPEG
                
                audio['covr'] = [MP4Cover(image_data, imageformat=cover_format)]
                audio.save()
            
            elif ext == '.mp3':
                try:
                    audio = ID3(file_path)
                except:
                    audio = ID3()
                
                audio['APIC'] = APIC(
                    encoding=3,
                    mime=mime_type,
                    type=3,  # Cover (front)
                    desc='Cover',
                    data=image_data
                )
                audio.save(file_path)
            
            elif ext == '.flac':
                audio = FLAC(file_path)
                
                picture = Picture()
                picture.type = 3  # Cover (front)
                picture.mime = mime_type
                picture.desc = 'Cover'
                picture.data = image_data
                
                audio.clear_pictures()
                audio.add_picture(picture)
                audio.save()
            
            logger.info(f"Successfully embedded cover art in {file_path}")
            return True
            
        except Exception as e:
            logger.error(f"Error embedding cover art in {file_path}: {e}")
            return False
    
    @staticmethod
    def extract_cover_art(file_path: str) -> Optional[bytes]:
        """
        Extract cover art from audio file
        
        Args:
            file_path: Path to audio file
            
        Returns:
            Image binary data or None
        """
        try:
            if not os.path.exists(file_path):
                return None
            
            ext = os.path.splitext(file_path)[1].lower()
            
            if ext == '.m4a' or ext == '.mp4':
                audio = MP4(file_path)
                covers = audio.get('covr', [])
                if covers:
                    return bytes(covers[0])
            
            elif ext == '.mp3':
                audio = ID3(file_path)
                for key in audio.keys():
                    if key.startswith('APIC'):
                        return audio[key].data
            
            elif ext == '.flac':
                audio = FLAC(file_path)
                if audio.pictures:
                    return audio.pictures[0].data
            
            return None
            
        except Exception as e:
            logger.error(f"Error extracting cover art from {file_path}: {e}")
            return None
