from __future__ import unicode_literals, division, absolute_import, print_function

__license__   = 'GPL v3'
__copyright__ = '2025, Digital Assassins'

from six import text_type as unicode
# Maintain backwards compatibility with older versions of Qt and calibre.
try:
    from qt.core import QLabel, QHBoxLayout, QVBoxLayout, Qt, QGroupBox, QCheckBox, QSpinBox, QComboBox, QLineEdit, QPlainTextEdit, QWidget
except ImportError:
    from PyQt5.Qt import QLabel, QHBoxLayout, QVBoxLayout, Qt, QGroupBox, QCheckBox, QSpinBox, QComboBox, QLineEdit, QPlainTextEdit, QWidget

from PyQt5 import QtCore, QtGui, QtWidgets

from calibre.gui2.metadata.config import ConfigWidget as DefaultConfigWidget
from calibre.utils.config import JSONConfig
from calibre.constants import CONFIG_DIR_MODE, config_dir
from calibre_plugins.ai_custom_tag_extractor.encode_ascii import ckc_ls
import json
import os

# Pull in translation files for _() strings
try:
    load_translations()
except NameError:
    pass # load_translations() added in calibre 1.9

AI_PLUGIN_MODE = "Extractor" ### used for sharing config files between plugins temporarily during dev

STORE_NAME = 'Options'
KEY_TIMEOUT_SECS = 'timeoutSecs'
KEY_AI_PLATFORM = 'aiPlatform'
KEY_PLATFORM_URL = 'aiPlatformUrl'
KEY_PLATFORM_API_KEY = 'aiPlatformApiKey'
KEY_PLATFORM_WORKSPACE = 'aiPlatformWorkspace'
#KEY_PROMPT_ENGINEERING = 'aiPromptEngineering'
KEY_SUMMARY_ENGINEERING = 'aiSummaryEngineering'
KEY_PROMPT_MODE = 'aiPromptMode'
KEY_CONTEXT_MODE = 'aiContextMode'
KEY_SAVE_MODE = 'aiSaveMode'
KEY_ADVANCED_QUESTIONS = 'aiAdvancedQuestions'

SUPPORTED_PLATFORMS = {
    0: "AnythingLLM",
    #1: "GPT4All",
    #2: "OpenWebUI"
}

PROMPT_MODES = {
    0:"Efficiency",
    1:"Accuracy",
}

CONTEXT_MODES = {
    0:"VectorDB",
    1:"FullContext",
}

SAVE_MODES = {
    0:"Review",
    1:"AutoSave",
}

DEFAULT_PLATFORM_URLS = {
    "AnythingLLM": "http://127.0.0.1:3001",
    "GPT4All": "http://127.0.0.1:3001",
    "OpenWebUI": "http://127.0.0.1:3001"
}

BLOCK_LIST = {
    "anthropic.com",
    "cohere.com",
    "openai.com",
    "mistral.ai",
    "meta.com",
    "api.google.com"
}

DEFAULT_STORE_VALUES = {
    KEY_TIMEOUT_SECS: 600,
    KEY_AI_PLATFORM: "AnythingLLM",
    KEY_PLATFORM_URL: '',
    KEY_PLATFORM_API_KEY: '',
    KEY_PLATFORM_WORKSPACE: 'CalibreEbooks',
    KEY_SUMMARY_ENGINEERING: 'The Summary must be 4 paragraphs in length. If there is a story, do not provide any spoilers. I love lore, If there is any in the story, provide as much lore from the story as possible in the summary, unless revealing the lore would include a spoiler.',
    #KEY_PROMPT_ENGINEERING: 'I require a field called MainCharacter and i want you to provide the main character in the story if there is one.',
    KEY_PROMPT_MODE: 'Efficiency',
    KEY_CONTEXT_MODE: 'VectorDB',
    KEY_SAVE_MODE: 'Review',
    KEY_ADVANCED_QUESTIONS: [],
}

# This is where all preferences for this plugin will be stored
if AI_PLUGIN_MODE == "Extractor":
    plugin_prefs = JSONConfig('plugins/AI Custom Tag Extractor')
elif AI_PLUGIN_MODE == "Metadata":
    plugin_prefs = JSONConfig('plugins/AI Metadata')
    
PLUGIN_PATH = os.path.join(config_dir, 'plugins')

# Set defaults
plugin_prefs.defaults[STORE_NAME] = DEFAULT_STORE_VALUES

class ConfigWidget(QWidget):
    
    import calibre_plugins.ai_custom_tag_extractor.assets.platform_labels
    
    def create_advanced_questions(self, questions_path):
        try:
            with open(questions_path, "w") as file:
                file.write("In a field called {ISBN} I require the Book ISBN. ISBNs are normally located on the copyright page of the book. ISBNs are typically 10 or 13 digits long.")
                file.write("\n")
                file.write("In a field called {Publisher} I require the Book Publisher.")
                file.write("\n")
                file.write("In a field called {PublicationDate} I require the Date of Publication, Provide the earliest date. Do not provide File Dates or Today's Date. If you can't find a publication date, just return 'None'.")
                file.write("\n")
                file.write("In a field called {Author} I require the book Author.")
                file.write("\n")
                file.write("In a field called {Title} I require the book title from the book content, Do not return the Filename as the Title.")
                file.write("\n")
                file.write("In a field called {Genre} I require the Genre of the book or Literary Genres this book's content would fit into.")
                file.write("\n")
                file.write("In a field called {Summary}, Please provide your own Summary of the book. {SumEng}")
                file.write("\n")
            return True
        except Exception as e:
            return e
        
    def get_advanced_questions(self):
        questions_path = PLUGIN_PATH + os.sep + "AIMetadata-Advanced-Questions.txt"
        
        try:
            with open(questions_path, "r") as file:
                questions = [line.rstrip() for line in file]        
            questions = [q.replace('{ISBN}', 'ISBN').replace('{Publisher}', 'Publisher').replace('{PublicationDate}', 'Publication Date').replace('{Author}', 'Author').replace('{Title}', 'Title').replace('{Genre}', 'Genre').replace('{Summary}', 'Summary').replace('{SumEng}', str( self.pf_summary_engineering_msg.toPlainText() ).replace("|","").replace("\n","|") ) for q in questions]        
            return questions
            
        except Exception as e:            
            self.create_advanced_questions(questions_path)
            return False
        
    def initialise_advanced_questions(self):
        questions = self.get_advanced_questions()
        if questions == False:
            questions = self.get_advanced_questions()
            if questions == False:
                questions = self.get_advanced_questions()
        return
    
    def __init__(self):
        QWidget.__init__(self)
        self.prefs = plugin_prefs[STORE_NAME]
        
        ######################################################################################################################################
        ######################################################################################################################################
        ######################################################################################################################################
        ######################################################################################################################################
        
        self.resize(613, 558)
        self.mainVerticalLayout = QtWidgets.QVBoxLayout(self)
        self.mainVerticalLayout.setObjectName("mainVerticalLayout")
        self.platformOptionsGroupBox = QtWidgets.QGroupBox(self)
        self.platformOptionsGroupBox.setObjectName("platformOptionsGroupBox")
        self.platformOptionsVerticalLayout = QtWidgets.QVBoxLayout(self.platformOptionsGroupBox)
        self.platformOptionsVerticalLayout.setObjectName("platformOptionsVerticalLayout")
        self.aiPlatformlabel = QtWidgets.QLabel(self.platformOptionsGroupBox)
        self.aiPlatformlabel.setObjectName("aiPlatformlabel")
        self.platformOptionsVerticalLayout.addWidget(self.aiPlatformlabel)
        self.aiPlatformCombo = QtWidgets.QComboBox(self.platformOptionsGroupBox)
        self.aiPlatformCombo.setObjectName("aiPlatformCombo")
        self.platformOptionsVerticalLayout.addWidget(self.aiPlatformCombo)
        self.aiPlatformUrlLabel = QtWidgets.QLabel(self.platformOptionsGroupBox)
        self.aiPlatformUrlLabel.setObjectName("aiPlatformUrlLabel")
        self.platformOptionsVerticalLayout.addWidget(self.aiPlatformUrlLabel)
        self.aiPlatformUrlLineEdit = QtWidgets.QLineEdit(self.platformOptionsGroupBox)
        self.aiPlatformUrlLineEdit.setObjectName("aiPlatformUrlLineEdit")
        self.platformOptionsVerticalLayout.addWidget(self.aiPlatformUrlLineEdit)
        self.aiPlatformApiKeyLabel = QtWidgets.QLabel(self.platformOptionsGroupBox)
        self.aiPlatformApiKeyLabel.setObjectName("aiPlatformApiKeyLabel")
        self.platformOptionsVerticalLayout.addWidget(self.aiPlatformApiKeyLabel)
        self.aiPlatformApiKeyLineEdit = QtWidgets.QLineEdit(self.platformOptionsGroupBox)
        self.aiPlatformApiKeyLineEdit.setObjectName("aiPlatformApiKeyLineEdit")
        self.platformOptionsVerticalLayout.addWidget(self.aiPlatformApiKeyLineEdit)
        self.aiPlatformWorkspaceLabel = QtWidgets.QLabel(self.platformOptionsGroupBox)
        self.aiPlatformWorkspaceLabel.setObjectName("aiPlatformWorkspaceLabel")
        self.platformOptionsVerticalLayout.addWidget(self.aiPlatformWorkspaceLabel)
        self.aiPlatformWorkspaceLineEdit = QtWidgets.QLineEdit(self.platformOptionsGroupBox)
        self.aiPlatformWorkspaceLineEdit.setObjectName("aiPlatformWorkspaceLineEdit")
        self.platformOptionsVerticalLayout.addWidget(self.aiPlatformWorkspaceLineEdit)
        self.mainVerticalLayout.addWidget(self.platformOptionsGroupBox)
        
        self.promptEngineeringGroupBox = QtWidgets.QGroupBox(self)
        self.promptEngineeringGroupBox.setObjectName("promptEngineeringGroupBox")
        self.promptEngineeringVerticalLayout = QtWidgets.QVBoxLayout(self.promptEngineeringGroupBox)
        self.promptEngineeringVerticalLayout.setObjectName("promptEngineeringVerticalLayout")
        
        self.promptModeLabel = QtWidgets.QLabel(self.promptEngineeringGroupBox)
        self.promptModeLabel.setObjectName("promptModeLabel")
        self.promptEngineeringVerticalLayout.addWidget(self.promptModeLabel)
        self.promptModeCombo = QtWidgets.QComboBox(self.promptEngineeringGroupBox)
        self.promptModeCombo.setObjectName("promptModeCombo")
        self.promptEngineeringVerticalLayout.addWidget(self.promptModeCombo)
        
        self.contextModeLabel = QtWidgets.QLabel(self.promptEngineeringGroupBox)
        self.contextModeLabel.setObjectName("contextModeLabel")
        self.promptEngineeringVerticalLayout.addWidget(self.contextModeLabel)
        self.contextModeCombo = QtWidgets.QComboBox(self.promptEngineeringGroupBox)
        self.contextModeCombo.setObjectName("contextModeCombo")
        self.promptEngineeringVerticalLayout.addWidget(self.contextModeCombo)
        
        if AI_PLUGIN_MODE == "Metadata":
            self.summaryEngineeringLabel = QtWidgets.QLabel(self.promptEngineeringGroupBox)
            self.summaryEngineeringLabel.setObjectName("summaryEngineeringLabel")
            self.promptEngineeringVerticalLayout.addWidget(self.summaryEngineeringLabel)
            self.summaryEngineeringPlainText = QtWidgets.QPlainTextEdit(self.promptEngineeringGroupBox)
            self.summaryEngineeringPlainText.setObjectName("summaryEngineeringPlainText")
            self.promptEngineeringVerticalLayout.addWidget(self.summaryEngineeringPlainText)
        
        
        self.mainVerticalLayout.addWidget(self.promptEngineeringGroupBox)
        
        self.saveModeGroupBox = QtWidgets.QGroupBox(self)
        self.saveModeGroupBox.setObjectName("saveModeGroupBox")
        self.saveModeVerticalLayout = QtWidgets.QVBoxLayout(self.saveModeGroupBox)
        self.saveModeVerticalLayout.setObjectName("saveModeVerticalLayout")
        self.saveModeLabel = QtWidgets.QLabel(self.saveModeGroupBox)
        self.saveModeLabel.setObjectName("saveModeLabel")
        self.saveModeVerticalLayout.addWidget(self.saveModeLabel)
        self.saveModeCombo = QtWidgets.QComboBox(self.saveModeGroupBox)
        self.saveModeCombo.setObjectName("saveModeCombo")
        self.saveModeVerticalLayout.addWidget(self.saveModeCombo)
        
        self.mainVerticalLayout.addWidget(self.saveModeGroupBox)
        
        mainLayoutSpacer = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
        self.mainVerticalLayout.addItem(mainLayoutSpacer)
        self.footerHLayout = QtWidgets.QHBoxLayout()
        self.footerHLayout.setContentsMargins(0, 10, 0, 0)
        self.footerHLayout.setObjectName("footerHLayout")
        spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.footerHLayout.addItem(spacerItem1)
        self.anythingLlmLogo = QtWidgets.QLabel(self)
        self.anythingLlmLogo.setMaximumSize(QtCore.QSize(50, 50))
        self.anythingLlmLogo.setText("")
        self.anythingLlmLogo.setPixmap(QtGui.QPixmap(":images/anythingllm_icon.png"))
        self.anythingLlmLogo.setScaledContents(True)
        self.anythingLlmLogo.setObjectName("anythingLlmLogo")
        self.footerHLayout.addWidget(self.anythingLlmLogo)
        spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.footerHLayout.addItem(spacerItem2)
        self.gpt4AllLogo = QtWidgets.QLabel(self)
        self.gpt4AllLogo.setMaximumSize(QtCore.QSize(50, 50))
        self.gpt4AllLogo.setText("")
        self.gpt4AllLogo.setPixmap(QtGui.QPixmap(":images/gpt4all_icon.png"))
        self.gpt4AllLogo.setScaledContents(True)
        self.gpt4AllLogo.setObjectName("gpt4AllLogo")
        self.footerHLayout.addWidget(self.gpt4AllLogo)
        spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.footerHLayout.addItem(spacerItem3)
        self.openWebUiLogo = QtWidgets.QLabel(self)
        self.openWebUiLogo.setMaximumSize(QtCore.QSize(50, 50))
        self.openWebUiLogo.setText("")
        self.openWebUiLogo.setPixmap(QtGui.QPixmap(":images/openwebui_icon.png"))
        self.openWebUiLogo.setScaledContents(True)
        self.openWebUiLogo.setOpenExternalLinks(True)
        self.openWebUiLogo.setObjectName("openWebUiLogo")
        self.footerHLayout.addWidget(self.openWebUiLogo)
        spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.footerHLayout.addItem(spacerItem4)
        self.mainVerticalLayout.addLayout(self.footerHLayout)

        self.retranslateUi(self)
        QtCore.QMetaObject.connectSlotsByName(self)
        
        ## add the default values to combo box
        for sp_id in SUPPORTED_PLATFORMS:
            self.aiPlatformCombo.insertItem(sp_id, SUPPORTED_PLATFORMS[sp_id])
        
        for pm_id in PROMPT_MODES:
            self.promptModeCombo.insertItem(pm_id, PROMPT_MODES[pm_id])

        for cm_id in CONTEXT_MODES:
            self.contextModeCombo.insertItem(cm_id, CONTEXT_MODES[cm_id])
            
        for sm_id in SAVE_MODES:
            self.saveModeCombo.insertItem(sm_id, SAVE_MODES[sm_id])
        
        ## update the valuyes with the preferences
        self.aiPlatformUrlLineEdit.setText( self.prefs.get(KEY_PLATFORM_URL, DEFAULT_STORE_VALUES[KEY_PLATFORM_URL]) )
        self.aiPlatformApiKeyLineEdit.setText( self.prefs.get(KEY_PLATFORM_API_KEY, DEFAULT_STORE_VALUES[KEY_PLATFORM_API_KEY]) )
        self.aiPlatformWorkspaceLineEdit.setText( self.prefs.get(KEY_PLATFORM_WORKSPACE, DEFAULT_STORE_VALUES[KEY_PLATFORM_WORKSPACE]) )
        
        if AI_PLUGIN_MODE == "Metadata":
            self.summaryEngineeringPlainText.setPlainText( self.prefs.get(KEY_SUMMARY_ENGINEERING, DEFAULT_STORE_VALUES[KEY_SUMMARY_ENGINEERING]) )
        
        for sp_id in SUPPORTED_PLATFORMS:
            if str(SUPPORTED_PLATFORMS[sp_id]) == str( self.prefs.get(KEY_AI_PLATFORM, DEFAULT_STORE_VALUES[KEY_AI_PLATFORM]) ):
                self.aiPlatformCombo.setCurrentIndex(sp_id)
                
        for pm_id in PROMPT_MODES:
            if str(PROMPT_MODES[pm_id]) == str( self.prefs.get(KEY_PROMPT_MODE, DEFAULT_STORE_VALUES[KEY_PROMPT_MODE]) ):
                self.promptModeCombo.setCurrentIndex(pm_id)
                
        for cm_id in CONTEXT_MODES:
            if str(CONTEXT_MODES[cm_id]) == str( self.prefs.get(KEY_CONTEXT_MODE, DEFAULT_STORE_VALUES[KEY_CONTEXT_MODE]) ):
                self.contextModeCombo.setCurrentIndex(cm_id)
                
        for sm_id in SAVE_MODES:
            if str(SAVE_MODES[sm_id]) == str( self.prefs.get(KEY_SAVE_MODE, DEFAULT_STORE_VALUES[KEY_SAVE_MODE]) ):
                self.saveModeCombo.setCurrentIndex(sm_id)
        
        ## sort the set up validation later - TODO
        #self.aiPlatformUrlLineEdit.editingFinished.connect(self.validateConnection)
        #self.aiPlatformApiKeyLineEdit.editingFinished.connect(self.validateConnection)
        ######################################################################################################################################
        ######################################################################################################################################
        ######################################################################################################################################
        ######################################################################################################################################
        
     
    def save_settings(self):        
        new_prefs = {}
        new_prefs[KEY_AI_PLATFORM] = str( self.aiPlatformCombo.itemText(self.aiPlatformCombo.currentIndex()) )
        new_prefs[KEY_PLATFORM_URL] = ckc_ls( str( self.aiPlatformUrlLineEdit.text() ), DEFAULT_PLATFORM_URLS, str( self.aiPlatformCombo.itemText(self.aiPlatformCombo.currentIndex()) ) )
        new_prefs[KEY_PLATFORM_API_KEY] = str( self.aiPlatformApiKeyLineEdit.text() )
        new_prefs[KEY_PLATFORM_WORKSPACE] = str( self.aiPlatformWorkspaceLineEdit.text() )
        
        new_prefs[KEY_PROMPT_MODE] = str( self.promptModeCombo.itemText(self.promptModeCombo.currentIndex()) )
        new_prefs[KEY_CONTEXT_MODE] = str( self.contextModeCombo.itemText(self.contextModeCombo.currentIndex()) )
        new_prefs[KEY_SAVE_MODE] = str( self.saveModeCombo.itemText(self.saveModeCombo.currentIndex()) )
        
        ## update the new prefs
        plugin_prefs[STORE_NAME] = new_prefs
    
        
    def validateConnection(self):
        # we check if the settings work or we ask them to try again
        if self.aiPlatformApiKeyLineEdit.text() != "" and self.aiPlatformUrlLineEdit.text() != "":
            import calibre_plugins.ai_custom_tag_extractor.anything_llm as anythingllm
            if anythingllm.authorize():
                print("Authorisation Failed! We Couldn't Validate your settings, is the Platform running and the URL and API Key Correct ?")
            else: 
                print(True)
    
    def commit(self):
        DefaultConfigWidget.commit(self)
        new_prefs = {}
        new_prefs[KEY_AI_PLATFORM] = str( self.aiPlatformCombo.itemText(self.aiPlatformCombo.currentIndex()) )
        new_prefs[KEY_PLATFORM_URL] = ckc_ls( str( self.aiPlatformUrlLineEdit.text() ), DEFAULT_PLATFORM_URLS, str( self.aiPlatformCombo.itemText(self.aiPlatformCombo.currentIndex()) ) )
        new_prefs[KEY_PLATFORM_API_KEY] = str( self.aiPlatformApiKeyLineEdit.text() )
        new_prefs[KEY_PLATFORM_WORKSPACE] = str( self.aiPlatformWorkspaceLineEdit.text() )
        
        #new_prefs[KEY_PROMPT_ENGINEERING] = str( self.pf_prompt_engineering_msg.toPlainText() ).replace("|","").replace("\n","|")
        new_prefs[KEY_PROMPT_MODE] = str( self.promptModeCombo.itemText(self.promptModeCombo.currentIndex()) )        
        new_prefs[KEY_SUMMARY_ENGINEERING] = str( self.summaryEngineeringPlainText.toPlainText() )
        
        new_prefs[KEY_CONTEXT_MODE] = str( self.contextModeCombo.itemText(self.contextModeCombo.currentIndex()) )
        new_prefs[KEY_SAVE_MODE] = str( self.saveModeCombo.itemText(self.saveModeCombo.currentIndex()) )
        
        if self.promptModeCombo.itemText(self.promptModeCombo.currentIndex()) == "Accuracy":
            # initialise the default advanced questions
            self.initialise_advanced_questions()        
        new_prefs[KEY_ADVANCED_QUESTIONS] = self.get_advanced_questions()
        
        ## update the new prefs
        plugin_prefs[STORE_NAME] = new_prefs
      
    
    def retranslateUi(self, Dialog):
        _translate = QtCore.QCoreApplication.translate
        #self.setWindowTitle(_translate("Dialog", "Dialog"))
        self.platformOptionsGroupBox.setTitle(_translate("Dialog", "Platform Options"))
        self.aiPlatformlabel.setText(_translate("Dialog", "AI Platform to Communicate with:"))
        self.aiPlatformUrlLabel.setText(_translate("Dialog", "Platform URL:"))
        self.aiPlatformApiKeyLabel.setText(_translate("Dialog", "API Key:"))
        self.aiPlatformWorkspaceLabel.setText(_translate("Dialog", "Workspace:"))
        self.promptEngineeringGroupBox.setTitle(_translate("Dialog", "Prompt Engineering"))
        self.promptModeLabel.setText(_translate("Dialog", "Prompt Mode:"))
        self.contextModeLabel.setText(_translate("Dialog", "Context Mode:"))
        self.saveModeLabel.setText(_translate("Dialog", "Save Mode:"))
        
        if AI_PLUGIN_MODE == "Metadata":
            self.summaryEngineeringLabel.setText(_translate("Dialog", "Summary:"))