import json
import requests
from acrcloud.recognizer import ACRCloudRecognizer
from musixmatch_api import Musixmatch, CaptchaError, UserTokenError
from mutagen.mp3 import MP3
from mutagen.id3 import ID3, APIC, error


# ACRCloud API credentials
ACR_HOST = "identify-ap-southeast-1.acrcloud.com"
ACR_ACCESS_KEY = "fe9d03703ee501887c5570fff859bee9"
ACR_ACCESS_SECRET = "PFbmdVo4ZjRkT7AI3l1NLGGtGtsgIbC9vs1ydgYb"


# ACR Cloud configuration (update with your credentials)
config = {
    'host': ACR_HOST,
    'access_key': ACR_ACCESS_KEY,
    'access_secret': ACR_ACCESS_SECRET,
    'timeout': 10  # seconds
}

recognizer = ACRCloudRecognizer(config)

# Initialize Musixmatch API (exception handling to be added as per your implementation)
musixmatch = Musixmatch(Exception)

# Function to recognize a song using ACRCloud
def recognize_song(audio_file_path):
    buffer = open(audio_file_path, 'rb').read()
    result = recognizer.recognize_by_filebuffer(buffer, 0)
    try:
        result_dict = json.loads(result)
        return result_dict['metadata']['music'][0]
    except (KeyError, IndexError, json.JSONDecodeError) as e:
        print(f"Error while parsing result: {e}")
        return None

def format_time(ts):
    '''Converts time in seconds to the format [mm:ss.xx]'''
    minutes = int(ts // 60)
    seconds = int(ts % 60)
    hundredths = int((ts - int(ts)) * 100)
    return f'[{minutes:02d}:{seconds:02d}.{hundredths:02d}]'

def process_rich_sync_lyrics(rich_sync_lyrics_json):
    '''Converts Musixmatch rich sync data to LRC format'''
    lrc_lines = []
    try:
        # Load the JSON string into a Python object
        rich_sync_data = json.loads(rich_sync_lyrics_json)
    except json.JSONDecodeError as e:
        print(f"Error decoding JSON: {e}")
        return None

    # Iterate through each line and create formatted LRC lines
    for line in rich_sync_data:
        ts = format_time(line['ts'])  # Start time of the line
        lrc_line = f'{ts}{line["x"]}'  # Use "x" for the entire line of lyrics
        lrc_lines.append(lrc_line)

    # Join the formatted lines with line breaks
    return '\n'.join(lrc_lines)


# Function to get lyrics from Musixmatch given artist name and song title
def get_lyrics_from_musicxmatch(artist_name, song_title):
    try:
        user_token = musixmatch.get_user_token()
        track_data = musixmatch.get_search_by_track(song_title, artist_name, "")
        if track_data:
            track_id = track_data['track_id']
            rich_sync_data = musixmatch.get_rich_sync_by_id(track_id)
            
            # Print the JSON response for debugging
            print(json.dumps(track_data, indent=2))
            print(json.dumps(rich_sync_data, indent=2))

            if rich_sync_data and 'richsync_body' in rich_sync_data:
                rich_sync_lyrics_json = rich_sync_data['richsync_body']
                lrc_lyrics = process_rich_sync_lyrics(rich_sync_lyrics_json)
                return lrc_lyrics
            else:
                print("No synced lyrics found.")
                return None
        else:
            print("Track not found in Musixmatch.")
            return None
    except (CaptchaError, UserTokenError) as e:
        print(f"Error while working with Musixmatch: {e}")
        return None

def download_album_cover(album_cover_url, save_path, size=(1400, 1400)):
    # Download the album cover image from the given URL
    response = requests.get(album_cover_url, stream=True)
    if response.status_code == 200:
        with open(save_path, 'wb') as file:
            for chunk in response:
                file.write(chunk)
        # Resize and save the image externally if size is specified
        if size:
            from PIL import Image
            im = Image.open(save_path)
            im = im.resize(size)
            im.save(save_path)
            
def download_small_cover(album_cover_url, save_path, size=(350, 350)):
    # If you want to save a smaller version separately
    download_album_cover(album_cover_url, save_path, size)
# Note: You should check the appropriate usage rights before downloading images from the internet

def embed_album_art(audio_file_path, album_cover_path):
    audio = MP3(audio_file_path, ID3=ID3)
    
    # Add ID3 tag if it doesn't exist
    try:
        audio.add_tags()
    except error as e:
        pass

    with open(album_cover_path, 'rb') as album_art:
        audio.tags.add(
            APIC(
                encoding=3, # 3 is for utf-8
                mime='image/jpeg', # image/jpeg or image/png
                type=3, # 3 is for the cover image
                desc=u'Cover',
                data=album_art.read()
            )
        )
    audio.save(v2_version=3)
# Note: This function assumes you have already downloaded the album cover at 'album_cover_path'

if __name__ == "__main__":
    audio_file_path = 'C:/Users/ILEG-i5-11/Downloads/Music/Unknown_file.mp3'  # Replace with actual path
    lrc_file_path = 'C:/Users/ILEG-i5-11/Downloads/Music/Unknown_file.lrc'  # Output LRC file path

    # Recognize the song using ACRCloud
    song_tags = recognize_song(audio_file_path)
    if song_tags:
        artist_name = song_tags['artists'][0]['name']
        song_title = song_tags['title']
        print(f"Identified Song: {artist_name} - {song_title}")

        # Fetch track data using the recognized song's title and artist name
        track_data = musixmatch.get_search_by_track(song_title, artist_name)
        if track_data:
            track_id = track_data['track_id']

            # Fetch the album cover URL using the track ID
            album_cover_url = musixmatch.get_album_cover_url_by_track_id(track_id)
            if album_cover_url:
                album_cover_save_path = 'C:/Users/ILEG-i5-11/Downloads/Music/Album_Cover.jpg'
                download_album_cover(album_cover_url, album_cover_save_path)  # Download the high-resolution cover
                print(f"Album cover saved to: {album_cover_save_path}")

                small_album_cover_save_path = 'C:/Users/ILEG-i5-11/Downloads/Music/Small_Album_Cover.jpg'
                download_small_cover(album_cover_url, small_album_cover_save_path)  # For embedding
                print(f"Small album cover saved to: {small_album_cover_save_path}")

                # Embed 350x350 album art into the MP3 file
                embed_album_art(audio_file_path, small_album_cover_save_path)
                print("Album art embedded into the MP3 file.")
            else:
                print("Could not get album cover.")

            # Fetch the synced lyrics using the recognized song's track ID
            rich_sync_data = musixmatch.get_rich_sync_by_id(track_id)
            if rich_sync_data and 'richsync_body' in rich_sync_data:
                rich_sync_lyrics_json = rich_sync_data['richsync_body']
                lrc_lyrics = process_rich_sync_lyrics(rich_sync_lyrics_json)
                if lrc_lyrics:
                    # Write the LRC lyrics to a file
                    with open(lrc_file_path, 'w', encoding='utf-8') as lrc_file:
                        lrc_file.write(lrc_lyrics)
                    print(f"Saved LRC file to: {lrc_file_path}")
                else:
                    print("No synced lyrics found.")
        else:
            print("Track not found in Musixmatch.")
    else:
        print("Could not identify the song.")

Identified Song: Nick Jonas - This Is Heaven
Traceback (most recent call last):
  File "C:\Users\ILEG-i5-11\Downloads\Compressed\Duplicate\checkfirst.py", line 146, in <module>
    track_data = musixmatch.get_search_by_track(song_title, artist_name)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: Musixmatch.get_search_by_track() missing 1 required positional argument: 'album_name'