import os
import sys
import time
import requests
import orangecanvas.application.canvasmain as canvasmain
import Orange.data
from AnyQt.QtWidgets import QApplication, QLabel
from Orange.widgets import widget, gui
from Orange.widgets.utils.signals import Input, Output
from Orange.widgets.settings import Setting
from AnyQt.QtWidgets import QLineEdit, QTextBrowser, QTextEdit

if "site-packages/Orange/widgets" in os.path.dirname(os.path.abspath(__file__)).replace("\\", "/"):
    from Orange.widgets.orangecontrib.AAIT.llm import answers
    from Orange.widgets.orangecontrib.AAIT.utils import thread_management
    from Orange.widgets.orangecontrib.AAIT.utils.import_uic import uic
    from Orange.widgets.orangecontrib.AAIT.utils.initialize_from_ini import apply_modification_from_python_file
else:
    from orangecontrib.AAIT.llm import answers
    from orangecontrib.AAIT.utils import thread_management
    from orangecontrib.AAIT.utils.import_uic import uic
    from orangecontrib.AAIT.utils.initialize_from_ini import apply_modification_from_python_file

@apply_modification_from_python_file(filepath_original_widget=__file__)
class OWDeep_Search(widget.OWWidget):
    name = "Deep Search"
    description = "Generate a response to a column 'prompt' with a LLM"
    icon = "icons/owqueryllm.svg"
    if "site-packages/Orange/widgets" in os.path.dirname(os.path.abspath(__file__)).replace("\\", "/"):
        icon = "icons_dev/owqueryllm.svg"
    gui = os.path.join(os.path.dirname(os.path.abspath(__file__)), "designer/owdeepsearch.ui")
    want_control_area = True
    priority = 1089

    class Inputs:
        api_key = Input("API KEY", Orange.data.Table)
        prompt = Input("Prompt", Orange.data.Table)

    class Outputs:
        response = Output("Response", Orange.data.Table)

    @Inputs.api_key
    def set_api_key(self, in_api_key: Orange.data.Table):
        if in_api_key is not None:
            if "api_key" not in in_api_key.domain:
                self.error("You need a column api_key");
                return
            self.api_key = str(in_api_key[0]["api_key"])  # ← cast en str
            self.line_api_key.setText(self.api_key)
            self.error(None)
            if self.autorun:
                self.run()


    @Inputs.prompt
    def set_prompt(self, in_prompt: Orange.data.Table):
        if in_prompt is not None:
            if "prompt" not in in_prompt.domain:
                self.error("You need a column prompt");
                return
            self.prompt = str(in_prompt[0]["prompt"])  # ← cast en str
            self.error(None)
            if self.autorun:
                self.run()

    def __init__(self):
        super().__init__()
        # Qt Management
        self.setFixedWidth(700)
        self.setFixedHeight(500)
        uic.loadUi(self.gui, self)
        self.label_description = self.findChild(QLabel, 'Description')
        # canvasmain.CanvasMainWindow.set_signal_freeze(self, True)
        # print(self.label_description.text())
        self.line_api_key: QLineEdit = self.findChild(QLineEdit, "line_api_key")
        # Connexion du champ à la fonction de mise à jour
        self.line_api_key.editingFinished.connect(self.update_api_key)
        # Text browser
        self.textBrowser = self.findChild(QTextBrowser, 'textBrowser')
        # Data Management
        self.api_key = None
        self.prompt = None
        self.thread = None
        self.autorun = True
        self.can_run = True
        self.result = None  # sera ma table de sortie
        # Custom updates
        self.post_initialized()

    def update_api_key(self):
        self.api_key = self.line_api_key.text().strip()

    def deepsearch(self, api_key: str, prompt: str):
        """
        Appelle Perplexity Sonar Deep-Research et renvoie la réponse complète
        dans une Orange Table (métadonnée 'response').
        """

        url = "https://api.perplexity.ai/chat/completions"
        headers = {
            "Content-Type": "application/json",
            "Authorization": f"Bearer {api_key}"
        }
        payload = {
            "model": "sonar-deep-research",
            "messages": [
                {"role": "system",
                 "content": ("You are a deep research assistant. "
                             "Answer only in Markdown without exposing any chain-of-thought.")},
                {"role": "user", "content": prompt}
            ],
            "temperature": 0.0,
            "max_tokens": 20_000,
            "format": "markdown"
        }

        try:
            resp = requests.post(url, json=payload, headers=headers, timeout=600)
            resp.raise_for_status()
            answer_md = resp.json()["choices"][0]["message"]["content"]

        except requests.HTTPError as e:
            print("STATUS :", resp.status_code)  # affiche 400, 401, etc.
            print("DETAIL :", resp.text)  # message JSON complet de Perplexity

            answer_md = f"**Erreur Perplexity :** {resp.text}"

        except Exception as e:
            answer_md = f"**Erreur Perplexity :** {e}"

        # Affiche la réponse complète dans la console
        # print("Réponse Perplexity :\n", answer_md)

        response_var = Orange.data.StringVariable("response")

        domain = Orange.data.Domain([], metas=[response_var])
        out_data = Orange.data.Table.from_list(domain, [[answer_md]])
        #self.Outputs.response.send(out_data)
        return out_data

    def run(self):
        # print("I'm running...")
        # print(self.prompt)
        # print(self.api_key)
        if not self.can_run:
            return

        if self.prompt == None:
            return

        if self.api_key == None:
            # print("Je sors")
            return

        # If Thread is already running, interrupt it
        if self.thread is not None:
            if self.thread.isRunning():
                self.thread.safe_quit()

        # Start progress bar
        self.progressBarInit()
        #◙self.textBrowser.setText("")

        # Connect and start thread : main function, progress, result and finish
        # --> progress is used in the main function to track progress (with a callback)
        # --> result is used to collect the result from main function
        # --> finish is just an empty signal to indicate that the thread is finished
        self.thread = thread_management.Thread(self.deepsearch, self.api_key, self.prompt)
        self.thread.progress.connect(self.handle_progress)
        self.thread.result.connect(self.handle_result)
        self.thread.finish.connect(self.handle_finish)
        self.thread.start()

    def handle_progress(self, progress) -> None:
        value = progress[0]
        text = progress[1]
        if value is not None:
            self.progressBarSet(value)
        if text is None:
            self.textBrowser.setText("")
        else:
            self.textBrowser.insertPlainText(text)

    def handle_result(self, result):
        try:
            self.result = result
            self.Outputs.response.send(result)
            # Orange.canvas.freeze(True)
        except Exception as e:
            print("An error occurred when sending out_data:", e)
            self.Outputs.response.send(None)
            return

    def handle_finish(self):
        print("Generation finished")
        self.progressBarFinished()


    def post_initialized(self):
        pass


if __name__ == "__main__":
    app = QApplication(sys.argv)
    my_widget = OWDeep_Search()
    my_widget.show()
    app.exec_()

