# SmedgeRender.py
#
# Smedge integration with Nuke
#
# Smedge
# Copyright Uberware. All Rights Reserved

"""Common submit interface for Qt based DCCs."""

import logging
import typing
from uuid import UUID

from smedge.job import JobType
from smedge.pool import get_pools

try:
    from PySide6 import QtWidgets, QtCore
except ImportError:
    from PySide2 import QtWidgets, QtCore

SETTINGS_ORG = "Uberware"
SETTINGS_APP = "Smedge Submitter"
SETTINGS_POOLS = "Pools"

logger = logging.getLogger("smedge")

PropertiesType = typing.Dict[str, typing.Union[QtWidgets.QWidget, QtWidgets.QLayout]]


class SmedgeSubmitWindow(QtWidgets.QDialog):
    """A dialog box to override some details about how the job gets submitted."""

    def __init__(
        self,
        parent: typing.Optional[QtWidgets.QWidget] = None,
        frame_range: typing.Optional[typing.Tuple[int, int]] = None,
        packet_size: int = 1,
    ):
        """Initialize a new SmedgeSubmitWindow object."""
        # Set up the window
        super().__init__(parent=parent)
        self.setWindowTitle("Submit to Smedge")
        self.setMinimumWidth(450)
        self.main_layout = QtWidgets.QVBoxLayout()
        self.setLayout(self.main_layout)
        self.result_job_ids: typing.Optional[typing.List[UUID]] = None

        # Build the field widgets
        self.name = QtWidgets.QLineEdit("")
        self.name.setToolTip("The name for the job")

        self.frames = QtWidgets.QLineEdit(
            f"{frame_range[0]}-{frame_range[1]}" if frame_range else ""
        )
        self.frames.setToolTip("The frame range for the job")

        self.packet_size = QtWidgets.QSpinBox()
        self.packet_size.setRange(1, 10000)
        self.packet_size.setValue(packet_size)
        self.packet_size.setToolTip("The packet size for the job")

        frames_layout = QtWidgets.QHBoxLayout()
        frames_layout.addWidget(self.frames)
        frames_layout.addWidget(QtWidgets.QLabel("Packet Size:"))
        frames_layout.addWidget(self.packet_size)

        self.paused = QtWidgets.QCheckBox("")
        self.paused.setToolTip("Check to submit the job paused")

        self.priority = QtWidgets.QSlider(QtCore.Qt.Horizontal)
        self.priority.setRange(0, 100)
        self.priority.setValue(50)
        self.priority.setToolTip("The priority for the job")
        self.priority.valueChanged.connect(
            lambda: self.priority_value.setText(str(self.priority.value()))
        )

        self.priority_value = QtWidgets.QLabel(str(self.priority.value()))
        self.priority_value.setToolTip("The priority for the job")

        priority_layout = QtWidgets.QHBoxLayout()
        priority_layout.addWidget(self.paused)
        priority_layout.addSpacing(10)
        priority_layout.addWidget(QtWidgets.QLabel("Priority:"))
        priority_layout.addWidget(self.priority)
        priority_layout.addWidget(self.priority_value)

        self.pool = QtWidgets.QComboBox()
        self.pool.setToolTip("The pool for the job")
        self._load_pools()

        update_pools_button = QtWidgets.QPushButton("Update")
        update_pools_button.setMaximumWidth(80)
        update_pools_button.setToolTip("Get the current pools from Smedge")
        update_pools_button.clicked.connect(self._update_pools_button_pressed)

        pool_layout = QtWidgets.QHBoxLayout()
        pool_layout.addWidget(self.pool)
        pool_layout.addSpacing(10)
        pool_layout.addWidget(update_pools_button)

        self.note = QtWidgets.QLineEdit("")
        self.note.setToolTip("Add a note to the job")

        self.add_properties(
            {
                "Name": self.name,
                "Frames": frames_layout,
                "Paused": priority_layout,
                "Pool": pool_layout,
                "Note": self.note,
            }
        )
        # Create the submit button
        button = QtWidgets.QPushButton("Send to Smedge")
        button.clicked.connect(self._submit_button_pressed)
        button.setStyleSheet(
            "QPushButton {font-weight: bold; font-size: 18px; min-height: 32px;}"
        )
        button.setToolTip("Create and send jobs to Smedge")
        self.main_layout.addWidget(button)
        self.main_layout.addWidget(button)
        # Show the window
        self.show()
        logger.info("Smedge Submit Window created")

    def add_properties(self, properties: PropertiesType):
        """Add a grid of widgets in a property manager style."""
        group_box = QtWidgets.QGroupBox("Job Settings:")
        grid = QtWidgets.QGridLayout()
        grid.setColumnStretch(1, 1)
        row = 0
        for label, item in properties.items():
            grid.addWidget(QtWidgets.QLabel(f"{label}:"), row, 0)
            if isinstance(item, QtWidgets.QWidget):
                grid.addWidget(item, row, 1)
            else:
                grid.addLayout(item, row, 1)
            row += 1
        group_box.setLayout(grid)
        self.main_layout.addWidget(group_box)

    def submit(self, job: JobType) -> typing.List[UUID]:
        """Override this to handle the submitting as needed for each DCC.

        Args:
            job: The common data from the window at the time the user pressed the button

        Returns:
            the list of UUIDs returned from the Smedge submit API
        """
        logger.error(
            "The DCC submitter did not override the submit() method to work correctly"
        )
        raise NotImplementedError("Override this for your DCC submit window.")

    def _update_pools_button_pressed(self):
        """Update the pool list."""
        logger.info("Updating pool list...")
        self.pool.clear()
        self.pool.addItem("Whole System")
        settings = QtCore.QSettings(SETTINGS_ORG, SETTINGS_APP)
        pool_names = [pool.name for pool in get_pools()]
        self.pool.addItems(pool_names)
        settings.setValue(SETTINGS_POOLS, pool_names)
        logger.info("\n..." + "\n...".join(pool_names))
        settings.sync()

    def _submit_button_pressed(self):
        """Submit button callback to do the work."""
        logger.info("Submitting to Smedge...")
        # Build the base job
        job = {
            "Name": self.name.text(),
            "Range": self.frames.text(),
            "PacketSize": self.packet_size.value(),
            "Note": self.note.text(),
            "Status": -1 if self.paused.isChecked() else 0,
            "Priority": self.priority.value(),
            "Pool": self.pool.currentText(),
        }
        # Let the DCC handle the final details
        try:
            self.result_job_ids = self.submit(job)
            ids = "\n".join(str(job_id) for job_id in self.result_job_ids)
            message_box = ResultWindow(self, True, ids)
        except Exception as e:
            message_box = ResultWindow(self, False, str(e))
        message_box.show()
        message_box.exec()
        self.close()

    def _load_pools(self):
        """Load the pool list."""
        logger.debug("Loading pools...")
        self.pool.addItem("Whole System")
        settings = QtCore.QSettings(SETTINGS_ORG, SETTINGS_APP)
        for pool_name in settings.value(SETTINGS_POOLS, [], type=list):
            self.pool.addItem(pool_name)


class ResultWindow(QtWidgets.QDialog):
    """Show the submit result in a consistent way."""

    def __init__(self, parent: QtWidgets.QWidget, success: bool, details: str):
        """Initialize the result window."""
        super().__init__(parent)
        self.setWindowTitle(
            "Smedge submission successful" if success else "Smedge submission failed"
        )
        self.setMinimumWidth(350)
        layout = QtWidgets.QVBoxLayout()
        self.setLayout(layout)
        layout.addWidget(QtWidgets.QLabel("Job IDs:" if success else "Error:"))
        details_widget = QtWidgets.QTextEdit(details)
        details_widget.setReadOnly(True)
        layout.addWidget(details_widget)
        row = QtWidgets.QHBoxLayout()
        row.addStretch(1)
        close = QtWidgets.QPushButton("Close")
        close.clicked.connect(self.close)
        row.addWidget(close)
        layout.addLayout(row)
