import Orange
import os
import sys
from Orange.widgets import widget
from Orange.widgets.widget import Input, Output
from Orange.data import Table, Domain, StringVariable
from Orange.widgets.settings import Setting
from AnyQt.QtWidgets import QPushButton, QCheckBox, QRadioButton
if "site-packages/Orange/widgets" in os.path.dirname(os.path.abspath(__file__)).replace("\\", "/"):
    from Orange.widgets.orangecontrib.AAIT.utils.import_uic import uic
else:
    from orangecontrib.AAIT.utils.import_uic import uic
# ----------------------------------------------------------------------
# Entrée : in_data
# Sortie : out_data
#
# Règles :
# - on prend toutes les colonnes (features, target, metas)
# - une colonne doit s'appeler exactement "ColName"
# - les valeurs de cette colonne deviennent les noms des colonnes en sortie
# - ces valeurs doivent être toutes différentes et non vides
# - la sortie est une transposée
# - tout est sorti en StringVariable
# - la première colonne de sortie s'appelle aussi "ColName"
#   pour permettre une transposée de transposée
# ----------------------------------------------------------------------
class OWTableMutator(widget.OWWidget):
    name = "Table Mutator"
    description = "Apply a transform to a datatable."
    icon = "icons/apply_rules.svg"
    category = "AAIT - ALGORITHM"
    if "site-packages/Orange/widgets" in os.path.dirname(os.path.abspath(__file__)).replace("\\", "/"):
        icon = "icons_dev/OWmutator.svg"
    priority = 1145
    keywords = "transform datatable"
    gui = os.path.join(os.path.dirname(os.path.abspath(__file__)), "designer/owmutator.ui")
    want_control_area = False
    strauto: str = Setting('False')
    operation_mode: str = Setting("")

    class Inputs:
        data = Input("In data", Orange.data.Table)


    class Outputs:
        out_data = Output("Out data", Orange.data.Table)
    def __init__(self):
        super().__init__()
        # Qt Management
        self.setFixedWidth(470)
        self.setFixedHeight(300)
        uic.loadUi(self.gui, self)
        self.data=None
        self.checkbox_interface = self.findChild(QCheckBox, 'checkBox')
        self.radio_transpose = self.findChild(QRadioButton, 'radioButton_transpose')
        self.push_button_run = self.findChild(QPushButton, 'pushButton')
        if self.strauto == 'False':
            self.checkbox_interface.setChecked(False)
        else:
            self.checkbox_interface.setChecked(True)

        # Chargement radio depuis setting
        if self.operation_mode == "Transpose":
            self.radio_transpose.setChecked(True)
        else:
            self.radio_transpose.setChecked(False)

        self.push_button_run.clicked.connect(self.run)
        self.checkbox_interface.toggled.connect(self.on_auto_toggled)
        self.radio_transpose.toggled.connect(self.on_radio_transpose_toggled)
        if self.strauto == 'True':
            self.run()

    def on_auto_toggled(self, checked):
        if checked:
            self.strauto = "True"
        else:
            self.strauto = "False"

    def on_radio_transpose_toggled(self, checked):
        if checked:
            self.operation_mode = "Transpose"
        else:
            # si tu n'as qu'un seul radio bouton, décoché = aucun mode
            self.operation_mode = ""

    @Inputs.data
    def set_data(self, data):
        if data is None:
            self.Outputs.out_data.send(None)
            return
        self.data=data
        self.run()
    def run(self):
        if self.operation_mode == "Transpose":
            self.run_translate()
        else:
            self.error("please check an option")
            return

    def run_translate(self):
        self.error("")
        in_data=self.data
        if in_data is None:
            return

        if len(in_data) == 0:
            self.error("in_data est vide.")
            self.Outputs.out_data.send(None)
            return

        # Toutes les variables du domaine
        attrs = list(in_data.domain.attributes)
        class_vars = list(in_data.domain.class_vars)
        metas = list(in_data.domain.metas)

        all_vars = attrs + class_vars + metas

        if not all_vars:
            self.error("Aucune colonne trouvée dans in_data.")
            self.Outputs.out_data.send(None)
            return

        # Recherche de la colonne ColName
        colname_var = None
        for var in all_vars:
            if var.name == "ColName":
                colname_var = var
                break

        if colname_var is None:
            self.error("Erreur : aucune colonne nommée 'ColName' n'a été trouvée dans in_data.")
            self.Outputs.out_data.send(None)
            return


        # Conversion robuste vers string compatible Orange
        def cell_to_str(row, var):
            try:
                return var.str_val(row[var])
            except Exception:
                try:
                    s = str(row[var])
                    if s == "?" or s.lower() == "nan":
                        return ""
                    return s
                except Exception:
                    return ""

        # Récupération des futurs noms de colonnes depuis ColName
        future_col_names = [cell_to_str(row, colname_var) for row in in_data]

        # Vérification : non vides
        empty_positions = [i for i, v in enumerate(future_col_names) if v is None or str(v).strip() == ""]
        if empty_positions:
            self.error("Erreur : la colonne 'ColName' contient une ou plusieurs valeurs vides ou manquantes. Impossible de créer les noms de colonnes.")
            self.Outputs.out_data.send(None)
            return


        # Vérification : unicité
        seen = set()
        duplicates = []
        for v in future_col_names:
            if v in seen and v not in duplicates:
                duplicates.append(v)
            seen.add(v)

        if duplicates:
            self.error(f"Erreur : la colonne 'ColName' contient des doublons : "+ ", ".join(duplicates))
            self.Outputs.out_data.send(None)
            return

        # Colonnes à transposer = toutes sauf ColName
        vars_to_transpose = [var for var in all_vars if var != colname_var]

        if not vars_to_transpose:
            self.error("Erreur : aucune colonne à transposer en dehors de 'ColName'.")
            self.Outputs.out_data.send(None)
            return

        # Construction des lignes de sortie
        # 1ère valeur = nom de la colonne d'origine, stocké dans la colonne "ColName"
        # valeurs suivantes = valeurs par ligne d'origine
        rows_out = []
        for var in vars_to_transpose:
            new_row = [var.name]
            for row in in_data:
                new_row.append(cell_to_str(row, var))
            rows_out.append(new_row)

        # La première colonne s'appelle "ColName" pour permettre une re-transposée
        out_col_names = ["ColName"] + future_col_names

        # Tout en StringVariable
        out_meta_vars = [StringVariable(name) for name in out_col_names]
        out_domain = Domain([], metas=out_meta_vars)

        # Création table Orange
        out_data = Table.from_list(out_domain, rows_out)
        self.Outputs.out_data.send(out_data)


if __name__ == "__main__":
    from AnyQt.QtWidgets import QApplication

    app = QApplication(sys.argv)
    my_widget = OWTableMutator()
    my_widget.show()
    if hasattr(app, "exec"):
        app.exec()
    else:
        app.exec_()