import collections
import subprocess
import threading
import time
import re
from threading import Lock
from app import log

cmd = [
    "/usr/sbin/vlc",
    "--control", "rc",
    "--rc-fake-tty",
    "--quiet",
    "--aout=alsa",
    "--gain-init=0.0",
]

class VLCController:
    def __init__(self, cmd=cmd, volume=0, on_state_change=None):
        self.process = None
        self.volume = volume
        self.on_state_change = on_state_change  # 回调函数
        self.running = False
        self.playing = False
        self.current_state = -1
        self.url = ""
        self.reconnect = False
        self.output_history = collections.deque(maxlen=50)
        self.MAX_VLC_VOLUME = 256.0
        self.cmd = cmd
        self.cmd_lock = Lock()
        self.threadSendNull = None
    
    def _send_cmd_null(self):
        i = 0
        while self.process:
            if self.send_cmd("\r"):
                i += 1
                if i >= 10:
                    break
            time.sleep(0.5)
        log.logger.info("[VLC] send_cmd_null thread exited")

    def start_vlc(self):
        if self.process is not None:
            return

        self.process = subprocess.Popen(
            self.cmd,
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
            stderr=subprocess.STDOUT,
            universal_newlines=True,
            bufsize=1,
        )

        self.running = True

        self.threadSendNull = threading.Thread(target=self._send_cmd_null, daemon=True)
        self.threadSendNull.start()

        self.threadRead = threading.Thread(target=self._read_stdout, daemon=True)
        self.threadRead.start()
        log.logger.info("[VLC] started")

    def _read_stdout(self):
        """读取VLC输出并触发状态变化回调"""
        for line in self.process.stdout:
            line = line.strip()
            if not line:
                continue
            self.output_history.append(line)

            if "status change:" in line:
                m = re.search(r'status change: \( play state: (\w+)', line)
                if m:
                    new_state = int(m.group(1))
                    self.current_state = new_state
                    if self.on_state_change:
                        self.selfCallback(new_state)
                        self.on_state_change(new_state)

        self.running = False
        log.logger.info("[VLC] stdout thread exited")

    def send_cmd(self, cmd):
        """向VLC发送命令"""
        if not self.process or not self.process.stdin:
            # log.logger.error("[VLC] not started")
            return 1
        try:
            self.cmd_lock.acquire()
            self.process.stdin.write(cmd + "\n")
            self.process.stdin.flush()
            self.cmd_lock.release()
        except Exception as e:
            self.cmd_lock.release()
            log.logger.info("[VLC] send_cmd error")
            return 1
        return 0

    def play(self, url = "", volume = 0):
        """播放流"""
        if url == "":
            url = self.url
        else:
            self.url = url
        self.send_cmd("stop")
        self.send_cmd("clear")
        self.send_cmd(f"add {url}")
        self.send_cmd("play")
        log.logger.info(f"[VLC] playing {url}")

    def stop(self):
        """停止播放"""
        self.send_cmd("stop")
        self.current_state = -1

    def quit(self):
        """退出VLC"""
        if not self.process:
            return
        self.send_cmd("quit")
        self.process.stdin.close()
        self.process.wait(timeout=3)
        self.process = None
        self.running = False
        self.playing = False
        self.threadSendNull.join(timeout=2)
        self.threadSendNull = None
        self.current_state = -1
        self.url = ""
        self.reconnect = False
        self.on_state_change(5)
        log.logger.info("[VLC] stopped")
    
    def reconnect_player(self):
        self.reconnect = True
        while True:
            if not self.reconnect:
                break
            log.logger.info("[VLC] not playing, reconnecting...")
            self.send_cmd("play")
            time.sleep(3)
    
    def selfCallback(self, new_state):
        log.logger.info(f"[VLC] state changed to {new_state}")
        if new_state != 3 and new_state != 2 and not self.reconnect:  # 如果不是播放状态
            self.playing = False
            self.threadCheck = threading.Thread(target=self.reconnect_player,)
            self.threadCheck.start()
        else:
            if new_state == 3:
                self.playing = True
                self.reconnect = False
    
    def get_volume(self, timeout=1):
        """获取当前音量（返回百分比）"""
        if self.send_cmd("status"):
            return 0
        time.sleep(0.1)
        start = time.time()
        while time.time() - start < timeout:
                for l in reversed(self.output_history):
                    if "audio volume:" in l:
                        m = re.search(r"audio volume:\s*(\d+)", l)
                        if m:
                            raw = int(m.group(1))
                            volume = round(raw / self.MAX_VLC_VOLUME * 100.0)
                            return int(volume)
                time.sleep(0.1)
        return None
    
    def set_volume(self, volume):
        """按百分比设置音量（0–100%）"""
        volume = max(0, min(100, volume))
        self.volume = volume
        if not self.playing:
            return
        value = round(volume * self.MAX_VLC_VOLUME / 100.0)
        if self.process:
            self.send_cmd(f"volume {value}")
            log.logger.info(f"[VLC] set volume to {volume}")
    
    def get_state(self, timeout=1):
        # """获取当前播放状态 (play state 的值)"""
        # if self.send_cmd("status"):
        #     return -1
        # time.sleep(0.1)
        # start = time.time()
        # while time.time() - start < timeout:
        #     # 在最近输出中查找 play state
        #     for l in reversed(self.output_history):
        #         if "play state:" in l:
        #             m = re.search(r"play state:\s*(\d+)", l)
        #             if m:
        #                 return int(m.group(1))
        #     time.sleep(0.1)
        # return None
        return self.current_state
    
def state_callback(new_state):
    log.logger.info(f"[Callback] VLC state changed: {new_state}")

if __name__ == "__main__":
    vlc = VLCController(on_state_change=state_callback)
    vlc.start_vlc()
    vlc.play("http://192.168.11.109:8001/sourceId-13")
    vlc.set_volume(49)
    print(f"Current volume: {vlc.get_volume()}")
    time.sleep(3)
    vlc.set_volume(0)
    print(f"Current volume: {vlc.get_volume()}")
    time.sleep(3)
    vlc.set_volume(100)
    print(f"Current volume: {vlc.get_volume()}")
    
    while True:
        time.sleep(1)