import os
import re

from qgis.core import QgsSettings
from qgis.PyQt import QtCore, uic
from qgis.PyQt.QtWidgets import QButtonGroup, QWidget

BASE_SETTINGS_KEY = "/OpenLog/delimiter/"
DELIMITER_TYPE_KEY = "/delimiterType"


class DelimiterSelectionWidget(QWidget):
    def __init__(self, parent=None) -> None:
        """
        Widget to define delimiter (and escape and char quote for custom delimiter).

        Args:
            parent: parent widget
        """
        super().__init__(parent)

        # translation

        uic.loadUi(
            os.path.dirname(os.path.realpath(__file__))
            + "/delimiter_selection_widget.ui",
            self,
        )

        self.bgFileFormat = QButtonGroup(self)
        self.bgFileFormat.addButton(
            self.delimiterCSV, self.swFileFormat.indexOf(self.swpCSVOptions)
        )
        self.bgFileFormat.addButton(
            self.delimiterChars, self.swFileFormat.indexOf(self.swpDelimOptions)
        )

        self.bgFileFormat.buttonClicked.connect(
            lambda button: self.swFileFormat.setCurrentIndex(
                self.bgFileFormat.checkedId()
            )
        )

        # Select CSV by default
        self.delimiterCSV.setChecked(True)
        self._restore_setting()

        self.delimiterCSV.toggled.connect(self.delimiter_changed.emit)
        self.delimiterChars.toggled.connect(self.delimiter_changed.emit)
        self.cbxDelimComma.stateChanged.connect(self.delimiter_changed.emit)
        self.cbxDelimSpace.stateChanged.connect(self.delimiter_changed.emit)
        self.cbxDelimTab.stateChanged.connect(self.delimiter_changed.emit)
        self.cbxDelimSemicolon.stateChanged.connect(self.delimiter_changed.emit)
        self.cbxDelimColon.stateChanged.connect(self.delimiter_changed.emit)

    # Signal emitted when delimiter is changed.
    delimiter_changed = QtCore.pyqtSignal()

    def get_delimiter(self) -> str:
        """
        Get selected delimiter

        Returns: selected delimiter

        """
        self._save_setting()
        if self.delimiterCSV.isChecked():
            delimiter = ","
        else:
            delimiter = None
            if self._get_selected_delimiter():
                delimiter = "["
                delimiter += self._get_selected_delimiter()
                delimiter += "]"
        return delimiter

    def set_delimiter(self, delimiter: str) -> None:
        self.blockSignals(True)
        if "," in delimiter:
            self.delimiterCSV.setChecked(True)
        else:
            self.delimiterChars.setChecked(True)
        self._set_selected_delimiter(delimiter)
        self.blockSignals(False)

    def get_quote_char(self) -> str:
        """
        Get quote char

        Returns: quote char

        """
        if self.delimiterCSV.isChecked():
            quote_char = '"'
        else:
            quote_char = self.txtQuoteChars.text()
        return quote_char

    def get_escape_char(self) -> str:
        """
        Get escape char

        Returns: escape char

        """
        if self.delimiterCSV.isChecked():
            escape_char = None
        else:
            escape_char = self.txtEscapeChars.text()
        return escape_char

    def restore_settings(self, base_key: str):
        """
        Restore delimiter settings from QgsSetting()

        Args:
            base_key: base key for QgsSettings

        """
        settings = QgsSettings()
        delimiterType = settings.value(base_key + DELIMITER_TYPE_KEY, "")
        if delimiterType == "csv":
            self.delimiterCSV.setChecked(True)
        elif delimiterType == "chars":
            self.delimiterChars.setChecked(True)
        self.swFileFormat.setCurrentIndex(self.bgFileFormat.checkedId())

        delimiters = settings.value(base_key + "/delimiters")
        if delimiters:
            self._set_selected_delimiter(delimiters)

        self.txtQuoteChars.setText(settings.value(base_key + "/quoteChars", '"'))
        self.txtEscapeChars.setText(settings.value(base_key + "/escapeChars", '"'))

    def _restore_setting(self) -> None:
        """
        Restore delimiter settings from QgsSetting()

        """
        self.restore_settings(BASE_SETTINGS_KEY)

    def save_setting(self, base_key: str):
        """
        Store delimiter settings in QgsSettings()

        Args:
            base_key: base key for QgsSettings

        """
        settings = QgsSettings()
        if self.delimiterCSV.isChecked():
            settings.setValue(base_key + DELIMITER_TYPE_KEY, "csv")
        else:
            settings.setValue(base_key + DELIMITER_TYPE_KEY, "chars")
        settings.setValue(base_key + "/delimiters", self._get_selected_delimiter())
        settings.setValue(base_key + "/quoteChars", self.txtQuoteChars.text())
        settings.setValue(base_key + "/escapeChars", self.txtEscapeChars.text())

    def _save_setting(self) -> None:
        """
        Store delimiter settings in QgsSettings()

        """
        self.save_setting(BASE_SETTINGS_KEY)

    def _get_selected_delimiter(self) -> str:
        """
        Get selected delimiter in custom mode

        Returns: string with all selected custom delimiter

        """
        delimiter = ""
        if self.cbxDelimTab.isChecked():
            delimiter += "\t"
        if self.cbxDelimSpace.isChecked():
            delimiter += " "
        if self.cbxDelimColon.isChecked():
            delimiter += ":"
        if self.cbxDelimSemicolon.isChecked():
            delimiter += ";"
        if self.cbxDelimComma.isChecked():
            delimiter += ","

        delimiter += self.txtDelimiterOther.text()
        return delimiter

    def _set_selected_delimiter(self, delimiter: str) -> None:
        """
        Define selected delimiter in custom mode.
        String is parsed for all delimiter

        Args:
            delimiter: stored delimiter
        """
        self.cbxDelimComma.setChecked("," in delimiter)
        self.cbxDelimSpace.setChecked(" " in delimiter)
        self.cbxDelimTab.setChecked("\t" in delimiter)
        self.cbxDelimColon.setChecked(":" in delimiter)
        self.cbxDelimSemicolon.setChecked(";" in delimiter)

        chars = re.sub("[ ,:;\t]", "", delimiter)
        self.txtDelimiterOther.setText(chars)
