"""
novelWriter – GUI Doc Split Dialog
==================================

File History:
Created:   2020-02-01 [0.4.3]  GuiDocSplit
Rewritten: 2022-10-12 [2.0rc1] GuiDocSplit

This file is a part of novelWriter
Copyright (C) 2020 Veronica Berglyd Olsen and novelWriter contributors

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""  # noqa
from __future__ import annotations

import logging

from PyQt6.QtCore import pyqtSlot
from PyQt6.QtWidgets import (
    QAbstractItemView, QDialogButtonBox, QGridLayout, QLabel, QListWidget,
    QListWidgetItem, QVBoxLayout, QWidget
)

from novelwriter import SHARED
from novelwriter.enum import nwStandardButton
from novelwriter.extensions.configlayout import NColorLabel
from novelwriter.extensions.modified import NComboBox, NDialog
from novelwriter.extensions.switch import NSwitch
from novelwriter.types import QtAccepted, QtRoleAccept, QtRoleReject, QtUserRole

logger = logging.getLogger(__name__)


class GuiDocSplit(NDialog):
    """GUI: Document Split Tool."""

    LINE_ROLE  = QtUserRole
    LEVEL_ROLE = QtUserRole + 1
    LABEL_ROLE = QtUserRole + 2

    def __init__(self, parent: QWidget, sHandle: str) -> None:
        super().__init__(parent=parent)

        logger.debug("Create: GuiDocSplit")
        self.setObjectName("GuiDocSplit")

        self._data = {}
        self._text = []

        self.setWindowTitle(self.tr("Split Document"))

        self.headLabel = QLabel(self.tr("Document Headings"), self)
        self.headLabel.setFont(SHARED.theme.guiFontB)
        self.helpLabel = NColorLabel(
            self.tr("Select the maximum level to split into files."),
            self, color=SHARED.theme.helpText, wrap=True
        )

        # Values
        iPx = SHARED.theme.baseIconHeight

        options = SHARED.project.options
        spLevel = options.getInt("GuiDocSplit", "spLevel", 3)
        intoFolder = options.getBool("GuiDocSplit", "intoFolder", True)
        docHierarchy = options.getBool("GuiDocSplit", "docHierarchy", True)

        # Heading Selection
        self.listBox = QListWidget(self)
        self.listBox.setDragDropMode(QAbstractItemView.DragDropMode.NoDragDrop)
        self.listBox.setMinimumWidth(400)
        self.listBox.setMinimumHeight(180)

        self.splitLevel = NComboBox(self)
        self.splitLevel.addItem(self.tr("Split on Heading Level 1 (Partition)"),  1)
        self.splitLevel.addItem(self.tr("Split up to Heading Level 2 (Chapter)"), 2)
        self.splitLevel.addItem(self.tr("Split up to Heading Level 3 (Scene)"),   3)
        self.splitLevel.addItem(self.tr("Split up to Heading Level 4 (Section)"), 4)
        spIndex = self.splitLevel.findData(spLevel)
        if spIndex != -1:
            self.splitLevel.setCurrentIndex(spIndex)
        self.splitLevel.currentIndexChanged.connect(self._reloadList)

        # Split Options
        self.folderSwitch = NSwitch(self, height=iPx)
        self.folderSwitch.setChecked(intoFolder)
        self.folderLabel = QLabel(self.tr("Split into a new folder"), self)
        self.folderLabel.setBuddy(self.folderSwitch)

        self.hierarchySwitch = NSwitch(self, height=iPx)
        self.hierarchySwitch.setChecked(docHierarchy)
        self.hierarchyLabel = QLabel(self.tr("Create document hierarchy"), self)
        self.hierarchyLabel.setBuddy(self.hierarchySwitch)

        self.trashSwitch = NSwitch(self, height=iPx)
        self.trashLabel = QLabel(self.tr("Move split document to Trash"), self)
        self.trashLabel.setBuddy(self.trashSwitch)

        self.optBox = QGridLayout()
        self.optBox.addWidget(self.folderLabel,  0, 0)
        self.optBox.addWidget(self.folderSwitch, 0, 1)
        self.optBox.addWidget(self.hierarchyLabel,  1, 0)
        self.optBox.addWidget(self.hierarchySwitch, 1, 1)
        self.optBox.addWidget(self.trashLabel,  2, 0)
        self.optBox.addWidget(self.trashSwitch, 2, 1)
        self.optBox.setVerticalSpacing(8)
        self.optBox.setHorizontalSpacing(12)
        self.optBox.setColumnStretch(3, 1)

        # Buttons
        self.btnOk = SHARED.theme.getStandardButton(nwStandardButton.OK, self)
        self.btnOk.clicked.connect(self.accept)

        self.btnCancel = SHARED.theme.getStandardButton(nwStandardButton.CANCEL, self)
        self.btnCancel.clicked.connect(self.reject)

        self.btnBox = QDialogButtonBox(self)
        self.btnBox.addButton(self.btnOk, QtRoleAccept)
        self.btnBox.addButton(self.btnCancel, QtRoleReject)

        # Assemble
        self.outerBox = QVBoxLayout()
        self.outerBox.setSpacing(0)
        self.outerBox.addWidget(self.headLabel)
        self.outerBox.addWidget(self.helpLabel)
        self.outerBox.addSpacing(8)
        self.outerBox.addWidget(self.listBox)
        self.outerBox.addWidget(self.splitLevel)
        self.outerBox.addSpacing(8)
        self.outerBox.addLayout(self.optBox)
        self.outerBox.addSpacing(12)
        self.outerBox.addWidget(self.btnBox)
        self.setLayout(self.outerBox)

        # Load Content
        self._loadContent(sHandle)

        logger.debug("Ready: GuiDocSplit")

    def __del__(self) -> None:  # pragma: no cover
        logger.debug("Delete: GuiDocSplit")

    def data(self) -> tuple[dict, list[str]]:
        """Return the user's choices. Also save the users options for
        the next time the dialog is used.
        """
        headerList = []
        for i in range(self.listBox.count()):
            item = self.listBox.item(i)
            if item is not None:
                headerList.append((
                    item.data(self.LINE_ROLE),
                    item.data(self.LEVEL_ROLE),
                    item.data(self.LABEL_ROLE),
                ))

        spLevel = self.splitLevel.currentData()
        intoFolder = self.folderSwitch.isChecked()
        docHierarchy = self.hierarchySwitch.isChecked()
        moveToTrash = self.trashSwitch.isChecked()

        self._data["spLevel"] = spLevel
        self._data["headerList"] = headerList
        self._data["intoFolder"] = intoFolder
        self._data["docHierarchy"] = docHierarchy
        self._data["moveToTrash"] = moveToTrash

        logger.debug("Saving State: GuiDocSplit")
        options = SHARED.project.options
        options.setValue("GuiDocSplit", "spLevel", spLevel)
        options.setValue("GuiDocSplit", "intoFolder", intoFolder)
        options.setValue("GuiDocSplit", "docHierarchy", docHierarchy)

        return self._data, self._text

    @classmethod
    def getData(cls, parent: QWidget, handle: str) -> tuple[dict, list[str], bool]:
        """Pop the dialog and return the result."""
        dialog = cls(parent, handle)
        dialog.exec()
        data, text = dialog.data()
        accepted = dialog.result() == QtAccepted
        dialog.softDelete()
        return data, text, accepted

    ##
    #  Private Slots
    ##

    @pyqtSlot()
    def _reloadList(self) -> None:
        """Reload the content of the list box."""
        if sHandle := self._data.get("sHandle"):
            self._loadContent(sHandle)

    ##
    #  Internal Functions
    ##

    def _loadContent(self, sHandle: str) -> None:
        """Load content from a given source item."""
        self._data = {}
        self._data["sHandle"] = sHandle

        self.listBox.clear()

        nwItem = SHARED.project.tree[sHandle]
        if nwItem is None or not nwItem.isFileType():
            return

        spLevel = self.splitLevel.currentData()
        if not self._text:
            self._text = SHARED.project.storage.getDocumentText(sHandle).splitlines()

        for i, line in enumerate(self._text):

            pos = -1
            level = 0
            label = line.strip()
            if line.startswith("# ") and spLevel >= 1:
                pos = i
                level = 1
                label = line[2:].strip()
            elif line.startswith("## ") and spLevel >= 2:
                pos = i
                level = 2
                label = line[3:].strip()
            elif line.startswith("### ") and spLevel >= 3:
                pos = i
                level = 3
                label = line[4:].strip()
            elif line.startswith("#### ") and spLevel >= 4:
                pos = i
                level = 4
                label = line[5:].strip()
            elif line.startswith("#! ") and spLevel >= 1:
                pos = i
                level = 1
                label = line[3:].strip()
            elif line.startswith("##! ") and spLevel >= 2:
                pos = i
                level = 2
                label = line[4:].strip()
            elif line.startswith("###! ") and spLevel >= 3:
                pos = i
                level = 3
                label = line[5:].strip()

            if pos >= 0 and level > 0:
                trItem = QListWidgetItem()
                trItem.setText(line.strip())
                trItem.setData(self.LINE_ROLE, pos)
                trItem.setData(self.LEVEL_ROLE, level)
                trItem.setData(self.LABEL_ROLE, label)
                self.listBox.addItem(trItem)

        return
