import requests
import time
import threading
from typing import Dict, Optional, Any
from functools import wraps
from utils.logging_config import get_logger

logger = get_logger("audiodb_client")

# Global rate limiting variables
_last_api_call_time = 0
_api_call_lock = threading.Lock()
MIN_API_INTERVAL = 2.0  # 2 seconds between API calls (30 req/min free tier)

def rate_limited(func):
    """Decorator to enforce rate limiting on AudioDB API calls"""
    @wraps(func)
    def wrapper(*args, **kwargs):
        global _last_api_call_time

        with _api_call_lock:
            current_time = time.time()
            time_since_last_call = current_time - _last_api_call_time

            if time_since_last_call < MIN_API_INTERVAL:
                sleep_time = MIN_API_INTERVAL - time_since_last_call
                time.sleep(sleep_time)

            _last_api_call_time = time.time()

        from core.api_call_tracker import api_call_tracker
        api_call_tracker.record_call('audiodb')

        try:
            result = func(*args, **kwargs)
            return result
        except Exception as e:
            if "rate limit" in str(e).lower() or "429" in str(e):
                logger.warning(f"AudioDB rate limit hit, implementing backoff: {e}")
                time.sleep(4.0)
            raise e
    return wrapper


class AudioDBClient:
    """Client for interacting with TheAudioDB API"""

    BASE_URL = "https://www.theaudiodb.com/api/v1/json/2"

    def __init__(self):
        self.session = requests.Session()
        self.session.headers.update({
            'User-Agent': 'SoulSync/1.0',
            'Accept': 'application/json'
        })
        logger.info("AudioDB client initialized")

    @rate_limited
    def search_artist(self, artist_name: str) -> Optional[Dict[str, Any]]:
        """
        Search for an artist by name.

        Args:
            artist_name: Name of the artist to search for

        Returns:
            Artist dict from AudioDB or None if not found
        """
        try:
            response = self.session.get(
                f"{self.BASE_URL}/search.php",
                params={'s': artist_name},
                timeout=10
            )
            response.raise_for_status()

            data = response.json()
            artists = data.get('artists')

            if artists and len(artists) > 0:
                logger.debug(f"Found artist for query: {artist_name}")
                return artists[0]

            logger.debug(f"No artist found for query: {artist_name}")
            return None

        except Exception as e:
            logger.error(f"Error searching for artist '{artist_name}': {e}")
            return None

    @rate_limited
    def search_album(self, artist_name: str, album_title: str) -> Optional[Dict[str, Any]]:
        """
        Search for an album by artist name and album title.

        Args:
            artist_name: Name of the artist
            album_title: Title of the album

        Returns:
            Album dict from AudioDB or None if not found
        """
        try:
            response = self.session.get(
                f"{self.BASE_URL}/searchalbum.php",
                params={'s': artist_name, 'a': album_title},
                timeout=10
            )
            response.raise_for_status()

            data = response.json()
            albums = data.get('album')

            if albums and len(albums) > 0:
                logger.debug(f"Found album for query: {artist_name} - {album_title}")
                return albums[0]

            logger.debug(f"No album found for query: {artist_name} - {album_title}")
            return None

        except Exception as e:
            logger.error(f"Error searching for album '{artist_name} - {album_title}': {e}")
            return None

    @rate_limited
    def search_track(self, artist_name: str, track_title: str) -> Optional[Dict[str, Any]]:
        """
        Search for a track by artist name and track title.

        Args:
            artist_name: Name of the artist
            track_title: Title of the track

        Returns:
            Track dict from AudioDB or None if not found
        """
        try:
            response = self.session.get(
                f"{self.BASE_URL}/searchtrack.php",
                params={'s': artist_name, 't': track_title},
                timeout=10
            )
            response.raise_for_status()

            data = response.json()
            tracks = data.get('track')

            if tracks and len(tracks) > 0:
                logger.debug(f"Found track for query: {artist_name} - {track_title}")
                return tracks[0]

            logger.debug(f"No track found for query: {artist_name} - {track_title}")
            return None

        except Exception as e:
            logger.error(f"Error searching for track '{artist_name} - {track_title}': {e}")
            return None

    @rate_limited
    def lookup_artist_by_id(self, artist_id: str) -> Optional[Dict[str, Any]]:
        """Lookup an artist directly by AudioDB ID."""
        try:
            response = self.session.get(
                f"{self.BASE_URL}/artist.php",
                params={'i': artist_id},
                timeout=10
            )
            response.raise_for_status()
            data = response.json()
            artists = data.get('artists')
            if artists and len(artists) > 0:
                return artists[0]
            return None
        except Exception as e:
            logger.error(f"Error looking up artist by ID {artist_id}: {e}")
            return None

    @rate_limited
    def lookup_album_by_id(self, album_id: str) -> Optional[Dict[str, Any]]:
        """Lookup an album directly by AudioDB ID."""
        try:
            response = self.session.get(
                f"{self.BASE_URL}/album.php",
                params={'m': album_id},
                timeout=10
            )
            response.raise_for_status()
            data = response.json()
            albums = data.get('album')
            if albums and len(albums) > 0:
                return albums[0]
            return None
        except Exception as e:
            logger.error(f"Error looking up album by ID {album_id}: {e}")
            return None

    @rate_limited
    def lookup_track_by_id(self, track_id: str) -> Optional[Dict[str, Any]]:
        """Lookup a track directly by AudioDB ID."""
        try:
            response = self.session.get(
                f"{self.BASE_URL}/track.php",
                params={'m': track_id},
                timeout=10
            )
            response.raise_for_status()
            data = response.json()
            tracks = data.get('track')
            if tracks and len(tracks) > 0:
                return tracks[0]
            return None
        except Exception as e:
            logger.error(f"Error looking up track by ID {track_id}: {e}")
            return None
