"""
Spotify Module for Luke.

Gives Luke control over Bill's Spotify — now playing, recent tracks,
top artists, playback control, and playlist management.

WhatsApp commands:
  "what's playing" / "now playing" → current track
  "recent" / "recently played" → last 5 tracks
  "play [song/artist]" → search and play
  "pause" / "stop" → pause playback
  "skip" / "next" → skip to next track
  "queue [song]" → add to queue
  "top artists" / "top tracks" → listening stats
  "playlist [name]" → play a playlist by name
"""

import logging
from datetime import datetime

logger = logging.getLogger("spotify")

# Lazy-loaded client
_client = None
_available = None


def _get_client():
    """Get the Spotify client (lazy-loaded)."""
    global _client, _available
    if _available is None:
        try:
            from spotify_auth import get_spotify_client
            _client = get_spotify_client()
            _available = _client is not None
            if _available:
                logger.info("Spotify module: ACTIVE")
            else:
                logger.info("Spotify module: INACTIVE (run setup_spotify_auth.py)")
        except Exception as e:
            logger.error(f"Spotify init failed: {e}")
            _available = False
    return _client


def is_available():
    """Check if Spotify is connected."""
    _get_client()
    return _available


def now_playing():
    """Get the currently playing track."""
    sp = _get_client()
    if not sp:
        return "Spotify not connected. Run setup_spotify_auth.py — Luke"

    try:
        current = sp.current_playback()
        if not current or not current.get("is_playing"):
            return "Nothing playing right now. — Luke"

        item = current.get("item", {})
        track = item.get("name", "Unknown")
        artists = ", ".join(a["name"] for a in item.get("artists", []))
        album = item.get("album", {}).get("name", "")
        progress_ms = current.get("progress_ms", 0)
        duration_ms = item.get("duration_ms", 0)

        progress = f"{progress_ms // 60000}:{(progress_ms % 60000) // 1000:02d}"
        duration = f"{duration_ms // 60000}:{(duration_ms % 60000) // 1000:02d}"

        device = current.get("device", {}).get("name", "Unknown device")

        lines = [
            f"NOW PLAYING — Luke",
            f"{track}",
            f"by {artists}",
        ]
        if album:
            lines.append(f"Album: {album}")
        lines.append(f"{progress} / {duration} on {device}")

        return "\n".join(lines)

    except Exception as e:
        logger.error(f"Now playing error: {e}")
        return f"Couldn't get playback info: {str(e)[:80]} — Luke"


def recently_played(limit=5):
    """Get recently played tracks."""
    sp = _get_client()
    if not sp:
        return "Spotify not connected. Run setup_spotify_auth.py — Luke"

    try:
        recent = sp.current_user_recently_played(limit=limit)
        items = recent.get("items", [])

        if not items:
            return "No recent listening history. — Luke"

        lines = ["RECENTLY PLAYED — Luke", ""]
        for item in items:
            track = item["track"]
            name = track.get("name", "Unknown")
            artists = ", ".join(a["name"] for a in track.get("artists", []))
            played_at = item.get("played_at", "")
            # Parse time
            try:
                dt = datetime.fromisoformat(played_at.replace("Z", "+00:00"))
                time_str = dt.strftime("%-I:%M %p")
            except (ValueError, AttributeError):
                time_str = ""

            lines.append(f"  {name} — {artists}")
            if time_str:
                lines.append(f"    {time_str}")

        return "\n".join(lines)

    except Exception as e:
        logger.error(f"Recently played error: {e}")
        return f"Couldn't fetch recent tracks: {str(e)[:80]} — Luke"


def top_artists(time_range="medium_term", limit=5):
    """
    Get Bill's top artists.
    time_range: short_term (4 weeks), medium_term (6 months), long_term (all time)
    """
    sp = _get_client()
    if not sp:
        return "Spotify not connected. Run setup_spotify_auth.py — Luke"

    try:
        result = sp.current_user_top_artists(limit=limit, time_range=time_range)
        items = result.get("items", [])

        if not items:
            return "Not enough listening data yet. — Luke"

        range_label = {
            "short_term": "Last 4 Weeks",
            "medium_term": "Last 6 Months",
            "long_term": "All Time",
        }.get(time_range, time_range)

        lines = [f"TOP ARTISTS ({range_label}) — Luke", ""]
        for i, artist in enumerate(items, 1):
            name = artist.get("name", "Unknown")
            genres = ", ".join(artist.get("genres", [])[:2])
            lines.append(f"  {i}. {name}")
            if genres:
                lines.append(f"     {genres}")

        return "\n".join(lines)

    except Exception as e:
        logger.error(f"Top artists error: {e}")
        return f"Couldn't fetch top artists: {str(e)[:80]} — Luke"


def top_tracks(time_range="medium_term", limit=5):
    """Get Bill's top tracks."""
    sp = _get_client()
    if not sp:
        return "Spotify not connected. Run setup_spotify_auth.py — Luke"

    try:
        result = sp.current_user_top_tracks(limit=limit, time_range=time_range)
        items = result.get("items", [])

        if not items:
            return "Not enough listening data yet. — Luke"

        range_label = {
            "short_term": "Last 4 Weeks",
            "medium_term": "Last 6 Months",
            "long_term": "All Time",
        }.get(time_range, time_range)

        lines = [f"TOP TRACKS ({range_label}) — Luke", ""]
        for i, track in enumerate(items, 1):
            name = track.get("name", "Unknown")
            artists = ", ".join(a["name"] for a in track.get("artists", []))
            lines.append(f"  {i}. {name} — {artists}")

        return "\n".join(lines)

    except Exception as e:
        logger.error(f"Top tracks error: {e}")
        return f"Couldn't fetch top tracks: {str(e)[:80]} — Luke"


def play_search(query):
    """Search for a song/artist/playlist and start playing it."""
    sp = _get_client()
    if not sp:
        return "Spotify not connected. Run setup_spotify_auth.py — Luke"

    try:
        # Check for active device first
        devices = sp.devices()
        active = [d for d in devices.get("devices", []) if d.get("is_active")]
        any_device = devices.get("devices", [])

        if not active and not any_device:
            return "No Spotify devices found. Open Spotify on your phone or computer first. — Luke"

        device_id = active[0]["id"] if active else any_device[0]["id"]

        # Try playlist search first if query seems like a playlist name
        results = sp.search(q=query, type="playlist,track,artist", limit=3)

        # Check playlists
        playlists = results.get("playlists", {}).get("items", [])
        tracks = results.get("tracks", {}).get("items", [])
        artists = results.get("artists", {}).get("items", [])

        # Priority: exact playlist match > track > artist
        for pl in playlists:
            if query.lower() in pl["name"].lower():
                sp.start_playback(device_id=device_id, context_uri=pl["uri"])
                return f"Playing playlist: {pl['name']} ({pl['tracks']['total']} tracks) — Luke"

        if tracks:
            track = tracks[0]
            name = track["name"]
            artist_name = ", ".join(a["name"] for a in track.get("artists", []))
            sp.start_playback(device_id=device_id, uris=[track["uri"]])
            return f"Playing: {name} by {artist_name} — Luke"

        if artists:
            artist = artists[0]
            sp.start_playback(device_id=device_id, context_uri=artist["uri"])
            return f"Playing: {artist['name']} (artist radio) — Luke"

        return f"Couldn't find anything for '{query}'. Try being more specific. — Luke"

    except Exception as e:
        error_msg = str(e)
        if "NO_ACTIVE_DEVICE" in error_msg or "404" in error_msg:
            return "No active Spotify device. Open Spotify somewhere first. — Luke"
        logger.error(f"Play search error: {e}")
        return f"Playback error: {str(e)[:80]} — Luke"


def pause():
    """Pause playback."""
    sp = _get_client()
    if not sp:
        return "Spotify not connected. — Luke"

    try:
        sp.pause_playback()
        return "Paused. — Luke"
    except Exception as e:
        if "NO_ACTIVE_DEVICE" in str(e):
            return "Nothing is playing. — Luke"
        return f"Pause error: {str(e)[:80]} — Luke"


def resume():
    """Resume playback."""
    sp = _get_client()
    if not sp:
        return "Spotify not connected. — Luke"

    try:
        sp.start_playback()
        return "Resumed. — Luke"
    except Exception as e:
        if "NO_ACTIVE_DEVICE" in str(e):
            return "No active device. Open Spotify first. — Luke"
        return f"Resume error: {str(e)[:80]} — Luke"


def skip():
    """Skip to next track."""
    sp = _get_client()
    if not sp:
        return "Spotify not connected. — Luke"

    try:
        sp.next_track()
        # Brief pause then get the new track
        import time
        time.sleep(0.5)
        return now_playing()
    except Exception as e:
        return f"Skip error: {str(e)[:80]} — Luke"


def add_to_queue(query):
    """Search for a track and add it to the queue."""
    sp = _get_client()
    if not sp:
        return "Spotify not connected. — Luke"

    try:
        results = sp.search(q=query, type="track", limit=1)
        tracks = results.get("tracks", {}).get("items", [])

        if not tracks:
            return f"Couldn't find '{query}'. — Luke"

        track = tracks[0]
        name = track["name"]
        artists = ", ".join(a["name"] for a in track.get("artists", []))
        sp.add_to_queue(track["uri"])
        return f"Queued: {name} by {artists} — Luke"

    except Exception as e:
        return f"Queue error: {str(e)[:80]} — Luke"


def play_playlist(name):
    """Find and play one of Bill's playlists by name."""
    sp = _get_client()
    if not sp:
        return "Spotify not connected. — Luke"

    try:
        # Search Bill's own playlists first
        playlists = sp.current_user_playlists(limit=50)
        for pl in playlists.get("items", []):
            if name.lower() in pl["name"].lower():
                sp.start_playback(context_uri=pl["uri"])
                return f"Playing your playlist: {pl['name']} ({pl['tracks']['total']} tracks) — Luke"

        # Fallback to public search
        results = sp.search(q=name, type="playlist", limit=3)
        items = results.get("playlists", {}).get("items", [])
        if items:
            pl = items[0]
            sp.start_playback(context_uri=pl["uri"])
            return f"Playing: {pl['name']} by {pl['owner']['display_name']} ({pl['tracks']['total']} tracks) — Luke"

        return f"No playlist found matching '{name}'. — Luke"

    except Exception as e:
        if "NO_ACTIVE_DEVICE" in str(e):
            return "No active Spotify device. Open Spotify first. — Luke"
        return f"Playlist error: {str(e)[:80]} — Luke"


def new_releases(limit=20):
    """
    Check for new releases from artists Bill follows or listens to.
    Music drops on Fridays — Luke runs this Friday morning.

    Checks:
      1. Artists Bill follows
      2. Bill's top artists (last 6 months)
    Then finds any albums/singles released in the last 7 days.

    Returns formatted text with album links, or empty string if nothing new.
    """
    sp = _get_client()
    if not sp:
        return "Spotify not connected. Run setup_spotify_auth.py — Luke"

    try:
        from datetime import timedelta

        # Gather Bill's artists from two sources
        artist_ids = {}

        # 1. Followed artists
        try:
            followed = sp.current_user_followed_artists(limit=50)
            for artist in followed.get("artists", {}).get("items", []):
                artist_ids[artist["id"]] = artist["name"]
        except Exception:
            pass

        # 2. Top artists (medium term — last 6 months)
        try:
            top = sp.current_user_top_artists(limit=30, time_range="medium_term")
            for artist in top.get("items", []):
                artist_ids[artist["id"]] = artist["name"]
        except Exception:
            pass

        # 3. Top artists (short term — last 4 weeks, higher priority)
        try:
            top_recent = sp.current_user_top_artists(limit=20, time_range="short_term")
            for artist in top_recent.get("items", []):
                artist_ids[artist["id"]] = artist["name"]
        except Exception:
            pass

        if not artist_ids:
            return "No followed or top artists found yet. Listen more and try again. — Luke"

        # Check each artist's latest releases
        cutoff = (datetime.now() - timedelta(days=7)).strftime("%Y-%m-%d")
        new_drops = []

        for artist_id, artist_name in artist_ids.items():
            try:
                albums = sp.artist_albums(
                    artist_id,
                    album_type="album,single",
                    limit=5,
                    country="CA"  # Bill's in Canada
                )
                for album in albums.get("items", []):
                    release_date = album.get("release_date", "")
                    # Only include releases from the last 7 days
                    if release_date >= cutoff:
                        album_url = album.get("external_urls", {}).get("spotify", "")
                        album_type = album.get("album_type", "album")
                        total_tracks = album.get("total_tracks", 0)

                        new_drops.append({
                            "artist": artist_name,
                            "name": album.get("name", ""),
                            "type": album_type,
                            "tracks": total_tracks,
                            "date": release_date,
                            "url": album_url,
                        })
            except Exception:
                continue

            # Rate limit protection — don't hammer the API
            if len(new_drops) >= limit:
                break

        if not new_drops:
            return "No new drops from your artists this week. — Luke"

        # Deduplicate by album name (features can cause duplicates)
        seen = set()
        unique = []
        for drop in new_drops:
            key = f"{drop['artist']}:{drop['name']}".lower()
            if key not in seen:
                seen.add(key)
                unique.append(drop)

        # Sort: albums first, then singles, then by date
        unique.sort(key=lambda x: (0 if x["type"] == "album" else 1, x["date"]), reverse=True)

        lines = ["NEW MUSIC FRIDAY — Luke", ""]
        lines.append(f"{len(unique)} new release{'s' if len(unique) != 1 else ''} from your artists:")
        lines.append("")

        for drop in unique:
            type_label = "ALBUM" if drop["type"] == "album" else "SINGLE"
            lines.append(f"  {drop['artist']} — {drop['name']}")
            lines.append(f"    {type_label} ({drop['tracks']} tracks) • Released {drop['date']}")
            if drop["url"]:
                lines.append(f"    {drop['url']}")
            lines.append("")

        return "\n".join(lines)

    except Exception as e:
        logger.error(f"New releases error: {e}")
        return f"Couldn't check new releases: {str(e)[:80]} — Luke"


def weekly_music_summary(limit=5):
    """
    Get Bill's top tracks from the past 4 weeks with Spotify album links.
    Used in the weekly report.

    Returns a formatted text block or empty string if unavailable.
    """
    sp = _get_client()
    if not sp:
        return ""

    try:
        result = sp.current_user_top_tracks(limit=limit, time_range="short_term")
        items = result.get("items", [])

        if not items:
            return ""

        lines = ["YOUR WEEK IN MUSIC"]
        for i, track in enumerate(items, 1):
            name = track.get("name", "Unknown")
            artists = ", ".join(a["name"] for a in track.get("artists", []))
            album = track.get("album", {})
            album_name = album.get("name", "")

            # Build Spotify link to the album
            album_url = album.get("external_urls", {}).get("spotify", "")

            line = f"  {i}. {name} — {artists}"
            if album_name:
                line += f" ({album_name})"
            lines.append(line)
            if album_url:
                lines.append(f"     {album_url}")

        return "\n".join(lines)

    except Exception as e:
        logger.error(f"Weekly music summary error: {e}")
        return ""


def get_status():
    """Get Spotify status for dashboard health check."""
    return {
        "available": is_available(),
        "configured": bool(is_available() or _available is None),
    }
