from PySide2 import QtWidgets, QtCore
from ngSkinTools2 import cleanup, api, signal
from ngSkinTools2.api import VertexTransferMode
from ngSkinTools2.api.transfer import LayersTransfer
from ngSkinTools2.decorators import undoable
from ngSkinTools2.ui import qt, widgets, influenceMappingUI
from ngSkinTools2.ui.layout import createTitledRow, scale_multiplier
from ngSkinTools2.ui.session import session


class UiModel:
    def __init__(self):
        self.transfer = LayersTransfer()

    def destination_has_layers(self):
        l = api.Layers(self.transfer.target)
        return l.is_enabled() and len(l.list()) > 0

    @undoable
    def do_apply(self):
        self.transfer.complete_execution()
        from maya import cmds

        cmds.select(self.transfer.target)
        if session.active():
            session.events.targetChanged.emitIfChanged()


single_transfer_dialog_policy = qt.SingleWindowPolicy()


def open(parent, model):
    """

    :type model: UiModel
    """

    def buttonRow(window):
        def apply():
            model.do_apply()
            session.events.layerListChanged.emitIfChanged()
            window.close()

        return widgets.button_row(
            [
                ("Transfer", apply),
                ("Cancel", window.close),
            ]
        )

    def view_influences_settings():
        tabs.setCurrentIndex(1)

    def build_settings():
        result = QtWidgets.QVBoxLayout()

        vertexMappingMode = QtWidgets.QComboBox()
        vertexMappingMode.addItem("Closest point on surface", VertexTransferMode.closestPoint)
        vertexMappingMode.addItem("UV space", VertexTransferMode.uvSpace)
        vertexMappingMode.addItem("By vertex ID (source and destination vert count must match)", VertexTransferMode.vertexId)

        g = QtWidgets.QGroupBox("Selection")
        layout = QtWidgets.QVBoxLayout()
        g.setLayout(layout)

        sourceLabel = QtWidgets.QLabel()
        layout.addLayout(createTitledRow("Source:", sourceLabel))

        destinationLabel = QtWidgets.QLabel()
        layout.addLayout(createTitledRow("Destination:", destinationLabel))
        result.addWidget(g)

        g = QtWidgets.QGroupBox("Vertex mapping")
        layout = QtWidgets.QVBoxLayout()
        layout.addLayout(createTitledRow("Mapping mode:", vertexMappingMode))
        g.setLayout(layout)
        result.addWidget(g)

        g = QtWidgets.QGroupBox("Influences mapping")
        layout = QtWidgets.QVBoxLayout()
        g.setLayout(layout)

        edit = QtWidgets.QPushButton("Configure")
        qt.on(edit.clicked)(view_influences_settings)

        button_row = QtWidgets.QHBoxLayout()
        button_row.addWidget(edit)
        button_row.addStretch()
        layout.addLayout(button_row)

        result.addWidget(g)

        g = QtWidgets.QGroupBox("Other options")
        layout = QtWidgets.QVBoxLayout()
        g.setLayout(layout)

        keep_layers = QtWidgets.QCheckBox("Keep existing layers on destination")
        keep_layers_row = qt.wrap_layout_into_widget(createTitledRow("Destination layers:", keep_layers))
        layout.addWidget(keep_layers_row)

        @qt.on(keep_layers.stateChanged)
        def checked():
            model.transfer.keep_existing_layers = keep_layers.isChecked()

        result.addWidget(g)

        result.addStretch()

        def update_settings_to_model():
            keep_layers.setChecked(model.transfer.keep_existing_layers)
            vertexMappingMode.setCurrentIndex(vertexMappingMode.findData(model.transfer.vertex_transfer_mode))
            sourceTitle = model.transfer.source
            if model.transfer.source_file is not None:
                sourceTitle = 'file ' + model.transfer.source_file
            sourceLabel.setText("<strong>" + sourceTitle + "</strong>")
            destinationLabel.setText("<strong>" + model.transfer.target + "</strong>")
            keep_layers_row.setEnabled(model.destination_has_layers())

        @qt.on(vertexMappingMode.currentIndexChanged)
        def vertex_mapping_mode_changed():
            model.transfer.vertex_transfer_mode = vertexMappingMode.currentData()

        update_settings_to_model()

        return result

    def build_influenes_tab():
        infl_ui, _, recalcMatches = influenceMappingUI.build_ui(parent, model.transfer.influences_mapping)

        padding = QtWidgets.QVBoxLayout()
        padding.setContentsMargins(0, 20 * scale_multiplier, 0, 0)
        padding.addWidget(infl_ui)

        recalcMatches()

        return padding

    tabs = QtWidgets.QTabWidget()

    tabs.addTab(qt.wrap_layout_into_widget(build_settings()), "Settings")
    tabs.addTab(qt.wrap_layout_into_widget(build_influenes_tab()), "Influences mapping")

    window = QtWidgets.QDialog(parent)
    cleanup.registerCleanupHandler(window.close)
    window.setWindowTitle("Transfer")
    window.setAttribute(QtCore.Qt.WA_DeleteOnClose)
    window.resize(720 * scale_multiplier, 500 * scale_multiplier)
    window.setLayout(QtWidgets.QVBoxLayout())

    window.layout().addWidget(tabs)
    window.layout().addLayout(buttonRow(window))

    if session.active():
        session.addQtWidgetReference(window)

    single_transfer_dialog_policy.setCurrent(window)
    window.show()


def build_transfer_action(session, parent):
    from .actions import define_action
    from maya import cmds

    targets = []

    def detect_targets():
        targets[:] = []
        selection = cmds.ls(sl=True)
        if len(selection) != 2:
            return False

        if not api.Layers(selection[0]).is_enabled():
            return False

        targets[:] = selection

        return True

    def transfer_dialog(transfer):
        """

        :type transfer: LayersTransfer
        """
        model = UiModel()
        model.transfer = transfer
        open(parent, model)

    def handler():
        if not targets:
            return

        t = LayersTransfer()
        t.source = targets[0]
        t.target = targets[1]
        t.customize_callback = transfer_dialog
        t.execute()

    result = define_action(parent, "Transfer layers...", callback=handler)

    @signal.on(session.events.nodeSelectionChanged)
    def on_selection_changed():
        result.setEnabled(detect_targets())

    on_selection_changed()

    return result
