#!/usr/bin/env python3
import sys
import os
import time
import requests
from io import BytesIO
from PIL import Image
from api.auth import get_spotify_client
from rich.console import Console
from rich.panel import Panel
from rich.table import Table
from rich.text import Text
from rich import box
from rich.layout import Layout


def get_user_playlists(spotify_client):
    playlists = []
    results = spotify_client.current_user_playlists(limit=50)

    while results:
        playlists.extend(results["items"])
        if results["next"]:
            results = spotify_client.next(results)
        else:
            break

    return playlists


def format_duration(ms):
    """Convert milliseconds to MM:SS format"""
    seconds = ms // 1000
    minutes = seconds // 60
    seconds = seconds % 60
    return f"{minutes}:{seconds:02d}"


def get_current_playback(spotify):
    """Get currently playing track information"""
    try:
        playback = spotify.current_playback()
        if playback and playback.get("item"):
            track = playback["item"]
            artists = ", ".join([artist["name"] for artist in track.get("artists", [])])

            # Get album art URL (smallest size for terminal)
            album_images = track.get("album", {}).get("images", [])
            album_art_url = album_images[-1]["url"] if album_images else None  # Get smallest image

            return {
                "name": track.get("name", "Unknown"),
                "artists": artists,
                "album": track.get("album", {}).get("name", "Unknown"),
                "progress": playback.get("progress_ms", 0),
                "duration": track.get("duration_ms", 0),
                "is_playing": playback.get("is_playing", False),
                "album_art_url": album_art_url,
                "track_id": track.get("id", ""),  # To check if track changed
            }
    except:
        pass
    return None


def get_terminal_size():
    """Get terminal size in columns and rows"""
    try:
        columns, rows = os.get_terminal_size()
        return columns, rows
    except (OSError, AttributeError):
        return 80, 24  # Default fallback


def resize_image(image, max_width=None, max_height=None):
    """Resize image to fit terminal while maintaining aspect ratio"""
    if max_width is None or max_height is None:
        cols, rows = get_terminal_size()
        max_width = max_width or cols
        max_height = max_height or (rows - 2) * 2  # Unicode blocks are 2:1 ratio

    # Calculate scaling factor
    width, height = image.size
    scale = min(max_width / width, max_height / height)

    # Resize image
    new_width = int(width * scale)
    new_height = int(height * scale)

    # Ensure even height for half-block characters
    if new_height % 2 != 0:
        new_height -= 1

    # Use high-quality resampling for better results when downscaling
    return image.resize((new_width, new_height), Image.Resampling.LANCZOS)


def rgb_to_ansi(r, g, b, background=False):
    """Convert RGB to ANSI escape code"""
    if background:
        return f"\033[48;2;{r};{g};{b}m"
    else:
        return f"\033[38;2;{r};{g};{b}m"


def get_image_as_unicode_blocks(image_path, max_width=None, max_height=None, with_ansi=True):
    """
    Convert image to Unicode half-blocks (▄) for double vertical resolution
    Returns list of strings - with or without ANSI codes
    """
    if not image_path:
        return []

    try:
        # Load image
        if image_path.startswith("http"):
            # Handle URL
            response = requests.get(image_path)
            img = Image.open(BytesIO(response.content))
        else:
            # Handle local file
            img = Image.open(image_path)

        # Convert to RGB if necessary
        if img.mode != "RGB":
            img = img.convert("RGB")

        # Add slight blur for smoother appearance
        from PIL import ImageFilter

        img = img.filter(ImageFilter.GaussianBlur(radius=0.5))

        # Resize image
        img = resize_image(img, max_width, max_height)
        width, height = img.size

        pixels = img.load()

        # Process image using half-blocks for better resolution
        output = []
        for y in range(0, height, 2):  # Process 2 rows at a time
            row = ""
            for x in range(width):
                # Get top pixel
                if y < height:
                    r1, g1, b1 = pixels[x, y]
                else:
                    r1, g1, b1 = 0, 0, 0

                # Get bottom pixel
                if y + 1 < height:
                    r2, g2, b2 = pixels[x, y + 1]
                else:
                    r2, g2, b2 = 0, 0, 0

                if with_ansi:
                    # Use lower half block with top color as foreground and bottom as background
                    row += f"\033[38;2;{r2};{g2};{b2}m"  # Bottom pixel (foreground)
                    row += f"\033[48;2;{r1};{g1};{b1}m"  # Top pixel (background)
                    row += "▄"  # Lower half block character
                else:
                    # Just use a simple character based on brightness for curses
                    avg_brightness = (r1 + g1 + b1 + r2 + g2 + b2) // 6
                    if avg_brightness > 200:
                        row += "█"
                    elif avg_brightness > 150:
                        row += "▓"
                    elif avg_brightness > 100:
                        row += "▒"
                    elif avg_brightness > 50:
                        row += "░"
                    else:
                        row += " "

            if with_ansi:
                row += "\033[0m"  # Reset colors
            output.append(row)

        return output
    except:
        return []


def get_key():
    """Get a single keypress"""
    import termios, tty, sys

    fd = sys.stdin.fileno()
    old = termios.tcgetattr(fd)
    try:
        tty.setcbreak(fd)
        ch = sys.stdin.read(1)
        if ch == "\x1b":  # Arrow key
            ch += sys.stdin.read(2)
        return ch
    finally:
        termios.tcsetattr(fd, termios.TCSADRAIN, old)


def main():
    console = Console()

    # Authenticate first (outside of screen)
    try:
        console.print("Authenticating with Spotify...", style="yellow")
        spotify = get_spotify_client()
        user = spotify.current_user()
        username = user["display_name"]
    except Exception as e:
        console.print(f"Authentication failed: {str(e)}", style="red")
        console.print("Press any key to exit...")
        input()
        return

    # Load playlists
    try:
        console.print(f"Loading playlists for {username}...", style="yellow")
        playlists = get_user_playlists(spotify)
    except Exception as e:
        console.print(f"Failed to load playlists: {str(e)}", style="red")
        console.print("Press any key to exit...")
        input()
        return

    if not playlists:
        console.print("No playlists found!", style="red")
        console.print("Press any key to exit...")
        input()
        return

    # Now enter alternative screen mode like curses
    with console.screen(hide_cursor=True) as screen:
        # Main navigation variables
        current_row = 0
        scroll_offset = 0
        mode = "playlists"  # Can be "playlists" or "tracks"
        selected_playlist = None
        tracks = []

        # Playback caching
        cached_playback = None
        last_playback_fetch = 0
        playback_fetch_interval = 5  # Fetch every 5 seconds
        cached_album_art = []  # Cache rendered album art
        last_track_id = None

        def create_now_playing_panel():
            """Create now playing panel"""
            nonlocal cached_playback, last_playback_fetch, cached_album_art, last_track_id

            # Only fetch new data if cache is expired
            current_time = time.time()
            if current_time - last_playback_fetch > playback_fetch_interval:
                cached_playback = get_current_playback(spotify)
                last_playback_fetch = current_time

                # Check if track changed to reload album art
                if cached_playback and cached_playback.get("track_id") != last_track_id:
                    last_track_id = cached_playback.get("track_id")
                    # Load album art
                    if cached_playback.get("album_art_url"):
                        try:
                            cached_album_art = get_image_as_unicode_blocks(
                                cached_playback["album_art_url"],
                                max_width=40,
                                max_height=40,
                                with_ansi=True,
                            )
                        except Exception:
                            cached_album_art = []

            current = cached_playback
            if not current:
                return Panel(
                    Text("No track playing", style="dim italic", justify="center"),
                    title="[bold magenta]🎵 Now Playing[/bold magenta]",
                    border_style="magenta",
                )

            # Create content with album art and track info
            content_parts = []

            # Album art if available
            if cached_album_art:
                # Create a pre-formatted text block that preserves ANSI codes
                from rich.text import Text

                art_lines = []
                for line in cached_album_art:
                    art_lines.append(Text.from_ansi(line))

                # Join the lines with newlines
                art_text = Text()
                for i, line in enumerate(art_lines):
                    if i > 0:
                        art_text.append("\n")
                    art_text.append_text(line)

                content_parts.append(art_text)
                content_parts.append(Text())  # Empty line

            # Track info
            info_table = Table(show_header=False, box=None, padding=(0, 1))
            info_table.add_column("", style="dim", width=8)
            info_table.add_column("", style="white")

            # Status (Playing/Paused)
            status = "▶ Playing" if current["is_playing"] else "⏸ Paused"
            info_table.add_row("Status:", status)

            # Track details
            info_table.add_row("Track:", current["name"][:30])
            info_table.add_row("Artist:", current["artists"][:30])
            info_table.add_row("Album:", current["album"][:30])

            # Progress bar with estimated progress
            time_elapsed = (time.time() - last_playback_fetch) * 1000  # Convert to ms
            estimated_progress = current["progress"] + (
                time_elapsed if current["is_playing"] else 0
            )
            estimated_progress = min(
                estimated_progress, current["duration"]
            )  # Don't exceed duration

            progress_pct = (
                estimated_progress / current["duration"] if current["duration"] > 0 else 0
            )
            bar_width = 20
            filled = int(bar_width * progress_pct)
            empty = bar_width - filled
            progress_bar = "█" * filled + "░" * empty
            info_table.add_row("Progress:", progress_bar)

            # Time
            time_str = f"{format_duration(int(estimated_progress))} / {format_duration(current['duration'])}"
            info_table.add_row("Time:", time_str)

            if cached_album_art:
                from rich.console import Group

                content = Group(*content_parts, info_table)
            else:
                content = info_table

            return Panel(
                content, title="[bold magenta]🎵 Now Playing[/bold magenta]", border_style="magenta"
            )

        def create_layout():
            """Create the main layout"""
            nonlocal scroll_offset

            # Create layout
            layout = Layout()
            layout.split_row(
                Layout(name="main", ratio=3), Layout(name="now_playing", ratio=1, minimum_size=30)
            )

            # Calculate visible range
            visible_height = 15

            # Adjust scroll offset if needed
            if mode == "playlists":
                items = playlists
            else:
                items = tracks

            if current_row < scroll_offset:
                scroll_offset = current_row
            elif current_row >= scroll_offset + visible_height:
                scroll_offset = current_row - visible_height + 1

            if mode == "playlists":
                # Create playlist table
                playlist_table = Table(show_header=True, box=box.ROUNDED, expand=True)
                playlist_table.add_column("", width=3)
                playlist_table.add_column("Playlist", style="white", overflow="ellipsis", ratio=4)
                playlist_table.add_column("Tracks", style="green", justify="center", width=10)

                # Display playlists
                for i in range(visible_height):
                    idx = scroll_offset + i
                    if idx >= len(playlists):
                        playlist_table.add_row(" ", " ", " ")
                        continue

                    playlist = playlists[idx]
                    name = playlist["name"]
                    track_count = playlist.get("tracks", {}).get("total", 0)

                    # Add '>' indicator for selected item
                    indicator = "►" if idx == current_row else " "

                    style = "bold cyan" if idx == current_row else "white"
                    playlist_table.add_row(indicator, name, str(track_count), style=style)

                # Main content panel
                main_panel = Panel(
                    playlist_table,
                    title=f"[bold green]SPOTIFY PLAYLISTS ({len(playlists)} total)[/bold green]",
                    subtitle=f"[dim]↑↓: Navigate | Enter: View Tracks | Q: Quit | [{current_row + 1}/{len(playlists)}][/dim]",
                    border_style="green",
                )

            else:  # tracks mode
                # Create tracks table
                tracks_table = Table(show_header=True, box=box.ROUNDED, expand=True)
                tracks_table.add_column("", width=3)
                tracks_table.add_column("#", width=4, justify="right")
                tracks_table.add_column("Track", style="white", overflow="ellipsis", ratio=3)
                tracks_table.add_column("Artist", style="cyan", overflow="ellipsis", ratio=2)
                tracks_table.add_column("Duration", style="green", justify="center", width=10)

                # Display tracks
                for i in range(visible_height):
                    idx = scroll_offset + i
                    if idx >= len(tracks):
                        tracks_table.add_row(" ", " ", " ", " ", " ")
                        continue

                    track = tracks[idx]
                    name = track["name"]
                    artists = track["artists"]
                    duration = track["duration"]

                    # Add '>' indicator for selected item
                    indicator = "►" if idx == current_row else " "

                    style = "bold cyan" if idx == current_row else "white"
                    tracks_table.add_row(
                        indicator, str(idx + 1), name, artists, duration, style=style
                    )

                # Main content panel
                playlist_name = selected_playlist["name"] if selected_playlist else "Unknown"
                main_panel = Panel(
                    tracks_table,
                    title=f"[bold green]TRACKS: {playlist_name} ({len(tracks)} tracks)[/bold green]",
                    subtitle=f"[dim]↑↓: Navigate | Backspace: Back to Playlists | Q: Quit | [{current_row + 1}/{len(tracks)}][/dim]",
                    border_style="green",
                )

            layout["main"].update(main_panel)
            layout["now_playing"].update(create_now_playing_panel())

            return layout

        # Initial display
        screen.update(create_layout())

        # Main loop with single-key navigation
        while True:
            try:
                key = get_key()

                if key in ["q", "Q", "\x03"]:  # q or Ctrl+C
                    break

                if mode == "playlists":
                    if key == "\x1b[A":  # Up arrow
                        if current_row > 0:
                            current_row -= 1
                            screen.update(create_layout())
                    elif key == "\x1b[B":  # Down arrow
                        if current_row < len(playlists) - 1:
                            current_row += 1
                            screen.update(create_layout())
                    elif key in ["\r", "\n"]:  # Enter
                        # Load tracks for selected playlist
                        selected_playlist = playlists[current_row]

                        screen.update(
                            Panel(
                                f"Loading tracks for '{selected_playlist['name']}'...",
                                style="yellow",
                            )
                        )

                        try:
                            # Get all tracks from the playlist
                            results = spotify.playlist_tracks(selected_playlist["id"])
                            raw_tracks = results["items"]

                            # Handle pagination
                            while results["next"]:
                                results = spotify.next(results)
                                raw_tracks.extend(results["items"])

                            # Extract track information
                            tracks = []
                            for item in raw_tracks:
                                track_info = item.get("track")
                                if track_info:
                                    artists = ", ".join(
                                        [artist["name"] for artist in track_info.get("artists", [])]
                                    )
                                    tracks.append(
                                        {
                                            "name": track_info.get("name", "Unknown"),
                                            "artists": artists,
                                            "album": track_info.get("album", {}).get(
                                                "name", "Unknown"
                                            ),
                                            "duration": format_duration(
                                                track_info.get("duration_ms", 0)
                                            ),
                                        }
                                    )

                            if tracks:
                                mode = "tracks"
                                current_row = 0
                                scroll_offset = 0
                                screen.update(create_layout())
                            else:
                                screen.update(
                                    Panel(
                                        "No tracks found in this playlist!\n\nPress any key to go back...",
                                        style="red",
                                    )
                                )
                                get_key()
                                screen.update(create_layout())

                        except Exception as e:
                            screen.update(
                                Panel(
                                    f"Error loading tracks: {str(e)}\n\nPress any key to go back...",
                                    style="red",
                                )
                            )
                            get_key()
                            screen.update(create_layout())

                elif mode == "tracks":
                    if key == "\x1b[A":  # Up arrow
                        if current_row > 0:
                            current_row -= 1
                            screen.update(create_layout())
                    elif key == "\x1b[B":  # Down arrow
                        if current_row < len(tracks) - 1:
                            current_row += 1
                            screen.update(create_layout())
                    elif key in ["\x7f", "\x08"]:  # Backspace
                        # Go back to playlists
                        mode = "playlists"
                        current_row = 0
                        scroll_offset = 0
                        screen.update(create_layout())

            except KeyboardInterrupt:
                break
            except:
                continue

    # After exiting alternative screen, we're back to normal terminal
    console.print("\n[yellow]👋 Thanks for using Spotify Rich Browser![/yellow]")


if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        print("\n\nInterrupted by user")
    except Exception as e:
        print(f"\n\nError: {str(e)}")
        print("Note: Make sure you have the required dependencies.")
