# naomusic.py
# -*- encoding: UTF-8 -*-

import subprocess
import os
import json
import re
import time
import threading

class NaoMusicPlayer:
    def __init__(self, session, nao_ip, ssh_port=22):
        self.session = session
        self.player = session.service("ALAudioPlayer")
        self.nao_ip = nao_ip
        self.ssh_port = ssh_port
        self.music_dir = "/home/nao/music"
        self.local_path = "/tmp/song.mp3"
        self.remote_path = f"{self.music_dir}/song.mp3"
        try:
            subprocess.run(["sshpass", "-p", "nao", "ssh", "-p", str(self.ssh_port),
                             f"nao@{nao_ip}", f"mkdir -p {self.music_dir}"],
                         stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
        except: pass
        self.current_file = None
        self.current_task_id = None
        self.is_playing = False
        self.current_title = ""
        self.is_loading = False
        self.load_error = None
        self.status = ""
        self.progress = 0.0

    def search(self, query):
        try:
            cmd = ["yt-dlp", f"ytsearch5:{query}", "--flat-playlist", "--dump-json",
                   "--no-warnings", "--quiet"]
            result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
            entries = []
            for line in result.stdout.strip().splitlines():
                if not line.strip():
                    continue
                try:
                    data = json.loads(line)
                except json.JSONDecodeError:
                    continue
                vid = data.get("id")
                url = data.get("url")
                if not url or not url.startswith("http"):
                    url = f"https://www.youtube.com/watch?v={vid}" if vid else None
                if url:
                    entries.append({"url": url, "title": data.get("title", "Unknown")})
            return entries
        except Exception as e:
            print(f"Search error: {e}")
            return []

    _DL_PROGRESS_RE = re.compile(r'\[download\]\s+([\d.]+)%')

    def play(self, url, title):
        self.stop()
        self.current_title = title
        self.is_loading = True
        self.load_error = None
        self.status = "Starting download..."
        self.progress = 0.0
        try:
            if os.path.exists(self.local_path):
                os.remove(self.local_path)
        except: pass

        try:
            cmd = ["yt-dlp", url,
                   "-x", "--audio-format", "mp3",
                   "-o", self.local_path,
                   "--no-playlist", "--no-warnings", "--newline"]
            print(f"\n▶ yt-dlp {url}")
            proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
                                     text=True, bufsize=1)
            for line in proc.stdout:
                line = line.rstrip()
                if not line:
                    continue
                print(f"  [yt-dlp] {line}")
                m = self._DL_PROGRESS_RE.search(line)
                if m:
                    self.progress = float(m.group(1))
                    self.status = f"Downloading... {self.progress:.0f}%"
                elif "ExtractAudio" in line or "Extracting audio" in line:
                    self.status = "Converting to mp3..."
                elif line.startswith("[download] Destination"):
                    self.status = "Downloading..."
            proc.wait(timeout=120)

            if proc.returncode != 0 or not os.path.exists(self.local_path):
                print(f"Download failed (exit {proc.returncode})")
                self.load_error = "Download failed"
                return False

            size_mb = os.path.getsize(self.local_path) / (1024 * 1024)
            print(f"▶ scp {self.local_path} -> nao@{self.nao_ip}:{self.remote_path} ({size_mb:.1f} MB)")
            self.progress = 0.0
            upload_start = time.time()
            stop_ticker = threading.Event()

            def ticker():
                while not stop_ticker.is_set():
                    elapsed = time.time() - upload_start
                    self.status = f"Uploading to NAO ({size_mb:.1f} MB)... {elapsed:.0f}s"
                    stop_ticker.wait(1.0)

            t = threading.Thread(target=ticker, daemon=True)
            t.start()
            scp_result = subprocess.run(
                ["sshpass", "-p", "nao", "scp", "-P", str(self.ssh_port),
                 self.local_path, f"nao@{self.nao_ip}:{self.remote_path}"],
                capture_output=True, text=True, timeout=60
            )
            stop_ticker.set()
            t.join(timeout=1.0)
            print(f"  [scp] exit {scp_result.returncode}" +
                  (f": {scp_result.stderr.strip()}" if scp_result.stderr.strip() else ""))
            if scp_result.returncode != 0:
                print(f"SCP failed: {scp_result.stderr.strip()}")
                self.load_error = "SCP failed"
                return False

            self.current_file = self.remote_path
            self.status = "Playing"
            self.progress = 100.0
            self.current_task_id = self.player.playFile(self.remote_path)
            self.is_playing = True
            print(f"♪ Playing on NAO: {title} (task {self.current_task_id})")
            return True
        except Exception as e:
            print(f"Playback error: {e}")
            self.load_error = str(e)
            return False
        finally:
            self.is_loading = False

    def stop(self):
        try:
            self.player.stopAll()
        except Exception as e:
            print(f"Stop error: {e}")
        self.is_playing = False
        self.current_file = None
        self.current_task_id = None
        self.current_title = ""
