#!/usr/bin/python3

import os
import sys
from pathlib import Path
from PySide6.QtGui import (
    QAction,
    QPalette,
    QColor
)
from PySide6.QtWidgets import (
    QMainWindow,
    QWidget,
    QVBoxLayout,
    QHBoxLayout,
    QLabel,
    QMenu,
    QFileDialog,
    QPushButton,
    QLineEdit,
    QProgressBar,
)
from PySide6.QtUiTools import QUiLoader
from PySide6.QtCore import QFile

from MessageBus import MessageBus
from PelinkAboutDialog import PelinkAboutDialog

SCRIPT_PATH = Path(os.path.dirname(os.path.realpath(__file__)))
UI_PATH = SCRIPT_PATH / 'mainwindow.ui'

def load_ui(ui):
    loader = QUiLoader()
    ui_file = QFile(str(UI_PATH))
    ui_file.open(QFile.ReadOnly)
    widget = loader.load(ui_file)
    ui_file.close()
    return widget


class PelinkWindow:
    """
    parmeter on_launch: on_launch(state)
    """
    PROGRESS_STYLE_NORMAL = "" # Empty string resets style to default

    PROGRESS_STYLE_ERROR = ("""
        QProgressBar {
            border: 1px solid #555;
            border-radius: 4px;
            text-align: center;
        }

        QProgressBar::chunk {
            background-color: #EB4D4B;
        }
    """)

    def __init__(self, bus=None, on_launch=None):
        self.win = load_ui(UI_PATH)
        self.win.setWindowTitle("Pelink")
        self.win.setGeometry(0, 0, 800, 450)

        if bus:
            bus.progress.connect(self.bus_progress)
            bus.error.connect(self.bus_error)
            bus.peercount.connect(self.bus_peercount)

        self.movie_path = None
        self.cont_main = self.win.findChild(QWidget, "cont_main")
        self.cont_controls = self.win.findChild(QWidget, "cont_controls")

        self.but_select_file = self.win.findChild(QPushButton, "but_select_file")
        self.but_launch = self.win.findChild(QPushButton, "but_launch")
        self.but_retry = self.win.findChild(QPushButton, "but_retry")
        self.but_exit = self.win.findChild(QPushButton, "but_exit")

        self.label_file_name = self.win.findChild(QLabel, "label_file_name")
        self.label_error = self.win.findChild(QLabel, "label_error")
        self.label_progress_bar_placeholder = self.win.findChild(
            QLabel,
            "label_progress_bar_placeholder"
        )
        self.label_peers = self.win.findChild(QLabel, "label_peers")

        self.input_club = self.win.findChild(QLineEdit, "input_club")
        self.progress_bar = self.win.findChild(QProgressBar, "progress_bar")

        self.but_select_file.clicked.connect(self.action_select_movie)
        self.but_launch.clicked.connect(self.action_launch)
        self.but_retry.clicked.connect(self.action_retry)
        self.but_exit.clicked.connect(self.action_exit)
        self.input_club.textChanged.connect(self.on_input_club_change)

        self.menu_about = self.win.findChild(QAction, "menu_about")
        self.menu_about.triggered.connect(self.action_about)

        self.pelink_about_dialog = PelinkAboutDialog()

        self.on_launch = on_launch

        self.initial_state()

    def initial_state(self):
        self.screen_main()
        self.label_error.setText("")
        self.but_select_file.setEnabled(True)
        self.input_club.setEnabled(True)
        self.but_launch.show()
        self.progress_bar.show()
        self.progress_bar.setValue(0)
        self.progress_bar.setFormat("Set up")
        self.show_progress_bar(False)
        self.progress_bar.setStyleSheet(self.PROGRESS_STYLE_NORMAL)
        self.check_if_can_launch()

    def screen_main(self):
        self.cont_main.setVisible(True)
        self.cont_controls.setVisible(False)

    def screen_controls(self):
        self.cont_main.setVisible(False)
        self.cont_controls.setVisible(True)

    def close(self):
        self.win.close()

    def show(self):
        self.win.show()

    def show_progress_bar(self, show=True):
        if show:
            self.progress_bar.show()
            self.label_progress_bar_placeholder.hide()
        else:
            self.progress_bar.hide()
            self.label_progress_bar_placeholder.show()

    def check_if_can_launch(self) -> True:
        """
        Check if the settings allow to launch.
        Changes the Launch button enabled property.
        Returns True if ready, False otherwise
        """
        ok = True
        club = self.input_club.text()
        if not ok or not club or len(club) <= 3:
            ok = False
        if not ok or not self.movie_path:
            ok = False
        self.but_launch.setEnabled(ok)
        return ok

    def on_input_club_change(self, text):
        self.check_if_can_launch()

    def action_about(self):
        self.pelink_about_dialog.launch()

    def action_select_movie(self):
        file_path, _ = QFileDialog.getOpenFileName(
            self.win,
            "Select a file",
            "",
            "All Files (*);;Movies (*.mp4 *.mkv *.webm *.avi *.mov *.wmv)"
        )
        if file_path:
            self.movie_path = Path(file_path)
            self.label_file_name.setText(file_path)
        else:
            self.movie_path = None

        self.check_if_can_launch()

    def action_launch(self):
        print("Launch!")
        self.but_launch.setEnabled(False)
        self.but_select_file.setEnabled(False)
        self.input_club.setEnabled(False)
        self.set_progress(0, "Calling worker")
        self.show_progress_bar(True)

        if self.on_launch:
            self.on_launch(self.get_state())

    def action_retry(self):
        pass

    def action_exit(self):
        self.win.close()

    def set_progress(self, value=0, message=None):
        self.progress_bar.setValue(value)
        self.progress_bar.setFormat(message)

    def connection_failed(self, message=None):
        self.initial_state()
        self.show_progress_bar(True)
        self.label_error.setText(message)
        self.label_error.show()
        self.progress_bar.setStyleSheet(self.PROGRESS_STYLE_ERROR)
        self.set_progress(100, "Failed")

    def bus_progress(self, message:str, progress:int):
        """
        Event using MessageBus
        """
        self.set_progress(progress, message)
        if progress == 100:
            self.screen_controls()

    def bus_error(self, message:str):
        """
        Event using MessageBus
        """
        self.connection_failed(message)

    def bus_peercount(self, number:int):
        self.label_peers.setText(str(number))

    def get_state(self):
        return {
            "club": self.input_club.text(),
            "file_path": self.movie_path,
        }
