import os
import sys
import time
import requests
import subprocess
from PyQt5.QtWidgets import (
    QApplication, QMainWindow, QVBoxLayout, QListWidget, QWidget, QHBoxLayout,
    QListWidgetItem, QLabel, QSplitter, QFrame, QPushButton
)
from PyQt5.QtCore import Qt, QTimer
import vlc


class VideoFrame(QFrame):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setStyleSheet("background-color: black;")

    def mouseDoubleClickEvent(self, event):
        self.parent().toggle_fullscreen()


class VLCPlayer:
    def __init__(self, video_frame):
        self.instance = vlc.Instance()
        self.media_player = self.instance.media_player_new()
        self.video_frame = video_frame
        if sys.platform == "win32":
            self.media_player.set_hwnd(int(self.video_frame.winId()))
        else:
            self.media_player.set_xwindow(int(self.video_frame.winId()))

    def play_stream(self, url):
        if self.media_player.is_playing():
            self.media_player.stop()
            time.sleep(0.5)
        media = self.instance.media_new(url)
        media.add_option(":network-caching=3000")
        self.media_player.set_media(media)
        self.media_player.play()

    def stop(self):
        self.media_player.stop()

    def release(self):
        self.media_player.release()
        self.instance.release()


class IPTVWindow(QMainWindow):
    def __init__(self, php_dir):
        super().__init__()
        self.setWindowTitle("IPTV Player with EPG")
        self.setGeometry(0, 0, 1280, 720)
        self.php_dir = php_dir
        self._is_fullscreen = False
        self._normal_geometry = None
        self._normal_flags = None
        self.init_ui()
        self.download_playlist()

    def init_ui(self):
        # Main splitter
        self.splitter = QSplitter(Qt.Horizontal)

        # Left: Channel list
        self.channel_list = QListWidget()
        self.channel_list.itemClicked.connect(self.on_channel_clicked)
        self.splitter.addWidget(self.channel_list)

        # Right: Video + EPG + controls
        self.right_panel = QWidget()
        right_layout = QVBoxLayout(self.right_panel)
        right_layout.setContentsMargins(0, 0, 0, 0)
        right_layout.setSpacing(0)

        # Video frame
        self.video_frame = VideoFrame(self)
        right_layout.addWidget(self.video_frame, stretch=3)

        # EPG display
        self.epg_display = QLabel("EPG info will appear here")
        self.epg_display.setStyleSheet("background-color: #222; color: white; padding: 10px;")
        right_layout.addWidget(self.epg_display, stretch=1)

        # Controls
        self.controls = QWidget()
        control_layout = QHBoxLayout(self.controls)
        for name, func in [("⏮️", self.play_previous_channel),
                           ("⏯️", self.toggle_play_pause),
                           ("⏭️", self.play_next_channel),
                           ("🖵", self.toggle_fullscreen)]:
            btn = QPushButton(name)
            btn.clicked.connect(func)
            control_layout.addWidget(btn)
        right_layout.addWidget(self.controls)

        self.splitter.addWidget(self.right_panel)
        self.splitter.setSizes([300, 1000])
        self.setCentralWidget(self.splitter)

        # VLC player
        self.player = VLCPlayer(self.video_frame)

    def on_channel_clicked(self, item):
        url = item.data(Qt.UserRole)
        self.player.play_stream(url)
        def update_info(attempt=0):
            width = self.player.media_player.video_get_width()
            height = self.player.media_player.video_get_height()
            fps = self.player.media_player.get_fps()
            if width > 0 and height > 0:
                res = "SD"
                if width >= 3840: res = "4K"
                elif width >= 1920: res = "FHD"
                elif width >= 1280: res = "HD"
                text = f"{res}, {fps:.2f}FPS"
                base = item.text().split('(')[0].strip()
                item.setText(f"{base} ({text})")
            elif attempt < 10:
                QTimer.singleShot(500, lambda: update_info(attempt+1))
        QTimer.singleShot(800, lambda: update_info(0))

    def toggle_play_pause(self):
        if self.player.media_player.is_playing():
            self.player.media_player.pause()
        else:
            self.player.media_player.play()

    def play_next_channel(self):
        i = self.channel_list.currentRow()
        if i < self.channel_list.count()-1:
            self.channel_list.setCurrentRow(i+1)
            self.on_channel_clicked(self.channel_list.currentItem())

    def play_previous_channel(self):
        i = self.channel_list.currentRow()
        if i > 0:
            self.channel_list.setCurrentRow(i-1)
            self.on_channel_clicked(self.channel_list.currentItem())

    def toggle_fullscreen(self):
        if not self._is_fullscreen:
            # Save state
            self._normal_geometry = self.geometry()
            self._normal_flags = self.windowFlags()
            # Hide UI panels
            self.channel_list.hide()
            self.controls.hide()
            self.epg_display.hide()
            # Frameless and full screen via state
            self.setWindowFlags(Qt.FramelessWindowHint)
            self.show()
            self.setWindowState(self.windowState() | Qt.WindowFullScreen)
        else:
            # Restore state
            self.setWindowState(Qt.WindowNoState)
            self.setWindowFlags(self._normal_flags)
            self.show()
            if self._normal_geometry:
                self.setGeometry(self._normal_geometry)
            # Show UI
            self.channel_list.show()
            self.controls.show()
            self.epg_display.show()
        self._is_fullscreen = not self._is_fullscreen

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Escape and self._is_fullscreen:
            self.toggle_fullscreen()
        else:
            super().keyPressEvent(event)

    def download_playlist(self):
        try:
            os.makedirs(self.php_dir, exist_ok=True)
            url = "https://iptv.nywebforum.com/playlist.m3u"
            txt = requests.get(url, timeout=10).text.replace(
                "https://iptv.nywebforum.com", "http://localhost:8888"
            )
            path = os.path.join(self.php_dir, "playlist.m3u")
            with open(path, "w", encoding="utf-8") as f:
                f.write(txt)
            self.load_playlist(path)
        except Exception as e:
            print(f"Failed to download playlist: {e}")

    def load_playlist(self, path):
        try:
            with open(path, "r", encoding="utf-8") as f:
                lines = f.readlines()
            self.channel_list.clear()
            first = None
            name = None
            for l in lines:
                l = l.strip()
                if l.startswith("#EXTINF:"):
                    name = l.split(',')[-1].strip()
                elif l and not l.startswith("#") and name:
                    it = QListWidgetItem(f"{name} (Loading...)")
                    it.setData(Qt.UserRole, l)
                    self.channel_list.addItem(it)
                    if not first:
                        first = it
                    name = None
            if first:
                self.channel_list.setCurrentItem(first)
                QTimer.singleShot(800, lambda: self.on_channel_clicked(first))
        except Exception as e:
            print(f"Failed to load playlist: {e}")


def start_php_server(d, port=8888):
    try:
        os.chdir(d)
        return subprocess.Popen(["php", "-S", f"localhost:{port}"],
            stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
            creationflags=subprocess.CREATE_NO_WINDOW if sys.platform=="win32" else 0)
    except Exception:
        return None

if __name__ == "__main__":
    pd = os.path.join(os.path.dirname(__file__), "php_files")
    os.makedirs(pd, exist_ok=True)
    proc = start_php_server(pd)
    app = QApplication(sys.argv)
    w = IPTVWindow(pd)
    w.show()
    rc = app.exec_()
    w.player.stop()
    w.player.release()
    if proc:
        proc.terminate()
        try: proc.wait(2)
        except: proc.kill()
    sys.exit(rc)