#include "kamodelsettingpage.h"

#include "libukcc/widgets/SettingWidget/settinggroup.h"
#include "libukcc/widgets/SettingWidget/addbutton.h"
#include <kylin-ai/ai-base/modelconfig.h>
#include <kysdk/applications/kpasswordedit.h>

#include <QDir>
#include <QFile>
#include <QLabel>
#include <QFrame>
#include <QScrollBar>
#include <QComboBox>
#include <QTextEdit>
#include <QJsonObject>
#include <QJsonDocument>
#include <QPushButton>
#include <QGridLayout>
#include <QVBoxLayout>
#include <QSharedPointer>

#include "global/kaglobal.h"

class KAModelSettingPage::Private
{
public:
    QMap<RemoteModelId, S_Model> mapModel;
    QMap<RemoteModelId, UkccFrame*> mapModelUI;

    QLabel *labelModelSetting = nullptr;
    AddButton *buttonAddModel = nullptr;
    UkccFrame *addButtonFrame = nullptr;
    SettingGroup *settingGroup = nullptr;
};

KAModelSettingPage::KAModelSettingPage(QWidget *parent)
    : QWidget{parent},
      d_ptr(make_shared<Private>())
{
    initLayout();
}

KAModelSettingPage::~KAModelSettingPage()
{

}

void KAModelSettingPage::addItem(RemoteModelId type)
{
    if (d_ptr->mapModelUI.find(type) != d_ptr->mapModelUI.end())
        return;
    UkccFrame *itemFrame = new UkccFrame;
    itemFrame->setObjectName(QString("aaa ").append(type));
    QHBoxLayout *layItem = new QHBoxLayout(itemFrame);
    layItem->setContentsMargins(0, 0, 0, 0);

    KAModelItem *item = new KAModelItem(type);
    connect(item, &KAModelItem::sigEdit, [this](RemoteModelId type){editModel(type);});
    connect(item, &KAModelItem::sigDelete, this, &KAModelSettingPage::sigDelete);
    layItem->addWidget(item);

    d_ptr->mapModelUI[type] = itemFrame;
    qDebug() << itemFrame->objectName();
    d_ptr->settingGroup->addWidget(itemFrame);
}

void KAModelSettingPage::editModel(RemoteModelId &type)
{
    KAModelSettingDialog settingDialog(d_ptr->mapModel[type], this);
    if (settingDialog.exec())
    {
        // 重新加载 model 列表
    }
}

bool KAModelSettingPage::deleteModel(RemoteModelId &type)
{
    if (remove_remote_model_config(d_ptr->mapModel[type].modelVendorId, type) != SUCCEEDED)
    {
        // 删除失败
        return false;
    }
    // 删除成功
    d_ptr->mapModel.remove(type);
    d_ptr->settingGroup->removeWidget(d_ptr->mapModelUI[type]);
    d_ptr->mapModelUI.remove(type);
    if (type == NLP)
    {
        // 断开连接

    }

    // 删除配置，需要设置gsetting相关属性值为false。查询接口为 gsettings get org.kylin.aiassistant.settings is-vision-setup
    if (type == NLP) {
        g_gsettings->set("isNlpSetup", false);
    } else {
        // 发送信号告知已设置 vision 模型
        g_gsettings->set("isVisionSetup", false);
    }
    return true;
}

void KAModelSettingPage::addModel()
{
    KAModelSettingDialog settingDialog(this);
    if (settingDialog.exec())
    {
        reinitLayout();
        // 重新加载 model 列表
    }
}

void KAModelSettingPage::initLayout()
{
    QVBoxLayout *base_layout = new QVBoxLayout(this);

    d_ptr->labelModelSetting = new QLabel;
    d_ptr->labelModelSetting->setText(tr("Model Setting"));
    d_ptr->labelModelSetting->setContentsMargins(20, 0, 0, 0);
    QFont font("Noto Sans CJK SC", 11, QFont::DemiBold, false);
    d_ptr->labelModelSetting->setFont(font);
    base_layout->addWidget(d_ptr->labelModelSetting);

    d_ptr->settingGroup = new SettingGroup;
    {
        initConfig();

        initAddButton();

        base_layout->addWidget(d_ptr->settingGroup);

        base_layout->addStretch();
    }
}

/**
 * @brief KAModelSettingPage::reinitLayout
 *          重新布局（模型有变化的时候重新布局）
 */
void KAModelSettingPage::reinitLayout()
{
    // 清空 settinggroup 所有控件
    d_ptr->settingGroup->removeAndDeleteAllWidget();
    d_ptr->mapModelUI.clear();

    foreach (auto s_model, d_ptr->mapModel) {
        addItem(s_model.modelTypeId);
    }
    initAddButton();
}

/**
 * @brief KAModelSettingPage::initAddButton
 *          创建添加按钮
 */
void KAModelSettingPage::initAddButton()
{
    d_ptr->addButtonFrame = new UkccFrame;
    QHBoxLayout *layAddButton = new QHBoxLayout(d_ptr->addButtonFrame);
    layAddButton->setContentsMargins(0, 0, 0, 0);

    d_ptr->buttonAddModel = new AddButton;
    connect(d_ptr->buttonAddModel, &AddButton::clicked, this, &KAModelSettingPage::addModel);
    d_ptr->buttonAddModel->setFocusPolicy(Qt::NoFocus);

    layAddButton->addWidget(d_ptr->buttonAddModel);
    d_ptr->settingGroup->addWidget(d_ptr->addButtonFrame);
}

/**
 * @brief KAModelSettingPage::initConfig
 *          加载已配置模型,当前通过读取配置文件获取
 */
void KAModelSettingPage::initConfig()
{
    char *configJson =  new char[get_remote_model_config_length()];
    if (get_remote_model_config(configJson) != SUCCEEDED) {
        delete configJson;
        return;
    }

    QJsonDocument doc = QJsonDocument::fromJson(configJson);

    QJsonObject obj = doc.object();
    QStringList keys = obj.keys();
    foreach (QString key, keys) {
        foreach (QString ckey, obj.value(key).toObject().keys()) {
            loadOneModel(key.toInt(), ckey.toInt(), obj.value(key).toObject().value(ckey).toObject());
        }
    }

    delete configJson;
    return;
}

void KAModelSettingPage::loadOneModel(int mvid, int mtid, QJsonObject obj)
{
    S_Model structModel;
    structModel.modelVendorId = (RemoteModelVendorId)mvid;
    structModel.modelTypeId = (RemoteModelId)mtid;
    structModel.apiKey = obj.value("apiKey").toString();
    structModel.secretKey = obj.value("secretKey").toString();

    d_ptr->mapModel[structModel.modelTypeId] = structModel;

    addItem((RemoteModelId)mtid);
}

class KAModelSettingDialog::Private
{
public:
    S_Model model;
    bool isEdit = false;

    QLabel *labelModelVendor = nullptr;
    QLabel *labelModelType = nullptr;
    QLabel *labelApiKey = nullptr;
    QLabel *labelSecretKey = nullptr;
    QLabel *labelErrorInfo = nullptr;

    QComboBox *comboboxModelVendor = nullptr;
    QComboBox *comboboxModelType = nullptr;
    kdk::KPasswordEdit  *passwordEditApi = nullptr;
    kdk::KPasswordEdit *passwordEditSecret = nullptr;
//    QTextEdit *passwordEditApi = nullptr;
//    QTextEdit *passwordEditSecret = nullptr;

    QPushButton *buttonCancel = nullptr;
    QPushButton *buttonAccept = nullptr;

    QMap<RemoteModelVendorId, QVector<RemoteModelId>> mapRemoteAllModel;
};

KAModelSettingDialog::KAModelSettingDialog(S_Model model, QWidget *parent):
    KDialog{parent},
    d_ptr(make_shared<Private>())
{
    d_ptr->model = model;
    d_ptr->isEdit = true;
    initLayout();
    initUIData();

    d_ptr->comboboxModelVendor->setCurrentIndex((int)model.modelVendorId);
    d_ptr->comboboxModelVendor->setEnabled(false);
    updateModelTypeCombobox();

    setWindowTitle(tr("Edit model"));

    d_ptr->comboboxModelType->setCurrentIndex((int)model.modelTypeId);
    d_ptr->comboboxModelType->setEnabled(false);

//    d_ptr->passwordEditApi->setText(model.apiKey);
//    d_ptr->passwordEditSecret->setText(model.secretKey);
}

KAModelSettingDialog::KAModelSettingDialog(QWidget *parent):
    KDialog{parent},
    d_ptr(make_shared<Private>())
{
    d_ptr->isEdit = false;
    initLayout();
    initUIData();

    updateModelTypeCombobox();

    setWindowTitle(tr("Add model"));
    d_ptr->buttonAccept->setText(tr("Add"));

    updatePasswordEdit(0);
}

KAModelSettingDialog::~KAModelSettingDialog()
{

}

void KAModelSettingDialog::initLayout()
{
//    setWindowIcon(QIcon::fromTheme("kylin-aiassistant"));
    setWindowIcon(QIcon(":/icon/icon/AI-Writing.svg"));
//    setFixedSize(500, 340);
    setFixedSize(420, 308);

    d_ptr->labelModelVendor = new QLabel(tr("Model Vendor"));
    d_ptr->labelModelType = new QLabel(tr("Model Type"));
    d_ptr->labelApiKey = new QLabel("APIKey");
    d_ptr->labelSecretKey = new QLabel("SecretKey");

    d_ptr->comboboxModelVendor = new QComboBox;
    connect(d_ptr->comboboxModelVendor, &QComboBox::currentTextChanged, [this](QString str){updateModelTypeCombobox();});
    d_ptr->comboboxModelType = new QComboBox;
    connect(d_ptr->comboboxModelType, SIGNAL(currentIndexChanged(int)), this, SLOT(updatePasswordEdit(int)));

    d_ptr->passwordEditApi = new kdk::KPasswordEdit(nullptr);
    d_ptr->passwordEditApi->setFocusPolicy(Qt::WheelFocus);
    d_ptr->passwordEditSecret = new kdk::KPasswordEdit(nullptr);
    d_ptr->passwordEditSecret->setFocusPolicy(Qt::WheelFocus);
//    d_ptr->passwordEditApi = new QTextEdit(nullptr);
//    d_ptr->passwordEditApi->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
//    d_ptr->passwordEditApi->setLineWrapMode(QTextEdit::NoWrap);
//    d_ptr->passwordEditSecret = new QTextEdit(nullptr);
//    d_ptr->passwordEditSecret->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
//    d_ptr->passwordEditSecret->setLineWrapMode(QTextEdit::NoWrap);

    d_ptr->labelErrorInfo = new QLabel();
    d_ptr->labelErrorInfo->setStyleSheet("color:red");
    d_ptr->labelErrorInfo->setFixedHeight(20);

    d_ptr->buttonCancel = new QPushButton(tr("Cancel"));
    d_ptr->buttonCancel->setFixedHeight(40);
    d_ptr->buttonCancel->setFocusPolicy(Qt::NoFocus);
    d_ptr->buttonCancel->setProperty("useButtonPalette", true);
    connect(d_ptr->buttonCancel, &QPushButton::clicked, [this](){reject();});

    d_ptr->buttonAccept = new QPushButton(tr("Accept"));
    d_ptr->buttonAccept->setFixedHeight(40);
    d_ptr->buttonAccept->setFocusPolicy(Qt::NoFocus);
//    d_ptr->buttonAccept->setProperty("isImportant", true);
    d_ptr->buttonAccept->setEnabled(false);

    connect(d_ptr->buttonAccept, &QPushButton::clicked, [this](){
        if (d_ptr->passwordEditApi->text().length()> 0 && d_ptr->passwordEditSecret->text().length() > 0)
            accept();
        else
            reject();
    });
    connect(d_ptr->passwordEditApi,&KPasswordEdit::textChanged, this, &KAModelSettingDialog::switchButtonStateEditing1);
    connect(d_ptr->passwordEditSecret,&KPasswordEdit::textChanged, this, &KAModelSettingDialog::switchButtonStateEditing2);

    QHBoxLayout *buttonLayout = new QHBoxLayout;
    buttonLayout->setContentsMargins(0, 20, 0, 20);
    buttonLayout->addStretch();
    buttonLayout->addWidget(d_ptr->buttonCancel);
    buttonLayout->addWidget(d_ptr->buttonAccept);

    QGridLayout *gridLayout = new QGridLayout();
    gridLayout->addWidget(d_ptr->labelModelVendor, 0, 0);
    gridLayout->addWidget(d_ptr->labelModelType, 1, 0);
    gridLayout->addWidget(d_ptr->labelApiKey, 2, 0);
    gridLayout->addWidget(d_ptr->labelSecretKey, 3, 0);

    gridLayout->addWidget(d_ptr->comboboxModelVendor, 0, 1);
    gridLayout->addWidget(d_ptr->comboboxModelType, 1, 1);
    gridLayout->addWidget(d_ptr->passwordEditApi, 2, 1);
    gridLayout->addWidget(d_ptr->passwordEditSecret, 3, 1);
    gridLayout->addWidget(d_ptr->labelErrorInfo, 4, 1);
    gridLayout->addLayout(buttonLayout, 5, 1);

    QHBoxLayout *mainLayout = new QHBoxLayout(mainWidget());
    mainLayout->setContentsMargins(20, 20, 20, 40);
    mainLayout->addLayout(gridLayout);
}

/**
 * @brief KAModelSettingDialog::initUIData
 *          初始化所有模型数据
 */
void KAModelSettingDialog::initUIData()
{
    const RemoteModelVendorId* vids = get_remote_model_vendor_list();
    if (vids != nullptr)
    {
        // 厂商遍历
        for (int i = 0; i < get_remote_model_vendor_list_length(); i++)
        {
            d_ptr->comboboxModelVendor->addItem(modelVendorToString(vids[i]));
            const RemoteModelId* tids = get_remote_model_list(vids[i]);
            if (tids != nullptr)
            {
                // 类型遍历
                for (int j = 0; j < get_remote_model_list_length(vids[i]); j++)
                {
                    qDebug() << vids[i] << " || " << tids[j];
                    d_ptr->mapRemoteAllModel[vids[i]].push_back(tids[j]);
                }
            }
        }
    }

    QString passwdTip = tr("Must write");
    d_ptr->passwordEditApi->setPlaceholderText(passwdTip);
    d_ptr->passwordEditSecret->setPlaceholderText(passwdTip);
}

void KAModelSettingDialog::updatePasswordEdit(int index)
{
    if (parentWidget())
    {
        KAModelSettingPage *setting = static_cast<KAModelSettingPage*> (parentWidget());
        if (setting->d_ptr->mapModel.find((RemoteModelId)index) != setting->d_ptr->mapModel.end() && d_ptr->isEdit)
        {
//            d_ptr->isEdit = true;
            // 已有,改为编辑
            setWindowTitle(tr("Edit model"));
            d_ptr->buttonAccept->setText(tr("Accept"));

            S_Model model = setting->d_ptr->mapModel[(RemoteModelId)index];
            d_ptr->passwordEditApi->setEchoMode(QLineEdit::Normal);
            d_ptr->passwordEditApi->setEchoModeBtnVisible(false);
            d_ptr->passwordEditSecret->setEchoMode(QLineEdit::Normal);
            d_ptr->passwordEditSecret->setEchoModeBtnVisible(false);
            QString str = model.apiKey.left(4) + "****" + model.apiKey.right(4);
            d_ptr->passwordEditApi->setText(str);
            str.clear();
            str = model.secretKey.left(4) + "****" + model.secretKey.right(4);
            d_ptr->passwordEditSecret->setText(str);
        }
        else
        {
//            d_ptr->isEdit = false;
            setWindowTitle(tr("Add model"));
            d_ptr->buttonAccept->setText(tr("Add"));

            d_ptr->passwordEditApi->setText("");
            d_ptr->passwordEditSecret->setText("");
            d_ptr->labelErrorInfo->setText("");
        }
    }
}

QString KAModelSettingDialog::modelVendorToString(const RemoteModelVendorId &vid)
{
    switch (vid)
    {
    case BAIDU:
        return tr("BAIDU");
    default:
        return tr("No Vendor");
    }
}

QString KAModelSettingDialog::modelTypeToString(const RemoteModelId &vid)
{
    switch (vid)
    {
    case NLP:
        return tr("NLP Big Model");
    case VISION:
        return tr("VISION Big Model");
    default:
        return tr("No Big Model");
    }
}

void KAModelSettingDialog::accept()
{
    QJsonObject obj;
    obj.insert("apiKey", d_ptr->passwordEditApi->text());
    obj.insert("secretKey", d_ptr->passwordEditSecret->text());
//    obj.insert("apiKey", d_ptr->passwordEditApi->toPlainText());
//    obj.insert("secretKey", d_ptr->passwordEditSecret->toPlainText());

    //判断本地是否存在该模型
    KAModelSettingPage *setting = nullptr;
    setting = static_cast<KAModelSettingPage*> (parentWidget());
    if (d_ptr->isEdit == false){
        if (parentWidget()){
            if (setting->d_ptr->mapModel.find((RemoteModelId)(d_ptr->comboboxModelType->currentIndex())) != setting->d_ptr->mapModel.end()){
                d_ptr->labelErrorInfo->setText(tr("The model type already exists. Cannot be repeated!"));
                return;
            }
        }
    }

    ModelConfigResult ret =set_remote_model_config(
        (RemoteModelVendorId)(d_ptr->comboboxModelVendor->currentIndex()),
        (RemoteModelId)(d_ptr->comboboxModelType->currentIndex()),
        QJsonDocument(obj).toJson().toStdString().c_str());

    if (ret != SUCCEEDED)
    {
        // 设置失败
        qDebug() << "Setting : " << ret;
        if (ret == FAILED) {
            d_ptr->labelErrorInfo->setText(tr("There is currently no network available, please try again"));
            return;
        }

        d_ptr->labelErrorInfo->setText(tr("Add failed, please try again!"));
        return;
    }

    if (parentWidget())
    {
        S_Model model;
        model.modelVendorId = (RemoteModelVendorId)(d_ptr->comboboxModelVendor->currentIndex());
        model.modelTypeId = (RemoteModelId)(d_ptr->comboboxModelType->currentIndex());
        model.apiKey = d_ptr->passwordEditApi->text();
        model.secretKey = d_ptr->passwordEditSecret->text();
//        model.apiKey = d_ptr->passwordEditApi->toPlainText();
//        model.secretKey = d_ptr->passwordEditSecret->toPlainText();

        setting->d_ptr->mapModel[model.modelTypeId] = model;
        setting->reinitLayout();
    }

    // 保存配置，如果NLP设置成功的话重新创建会话
    if ((RemoteModelId)(d_ptr->comboboxModelType->currentIndex() == NLP))
    {
//        g_gsettings->set("isNlpSetup", true);
    }
    else
    {
        // 发送信号告知已设置 vision 模型
//        g_gsettings->set("isVisionSetup", true);
    }
    d_ptr->labelErrorInfo->setText("");
    return KDialog::accept();
}

void KAModelSettingDialog::updateModelTypeCombobox()
{
    d_ptr->comboboxModelType->clear();
    QVector<RemoteModelId> types = d_ptr->mapRemoteAllModel[(RemoteModelVendorId)d_ptr->comboboxModelVendor->currentIndex()];
    foreach (RemoteModelId type, types)
    {
        qDebug() << (RemoteModelVendorId)d_ptr->comboboxModelVendor->currentIndex() << " | " << type << modelTypeToString(type);
        d_ptr->comboboxModelType->addItem(modelTypeToString(type));
    }
}

void KAModelSettingDialog::switchButtonState()
{
    if (d_ptr->passwordEditApi->text().length()>= 12 && d_ptr->passwordEditSecret->text().length() >= 12)
    {
        d_ptr->buttonAccept->setEnabled(true);
        d_ptr->buttonAccept->setProperty("isImportant", true);
    }
    else
        d_ptr->buttonAccept->setEnabled(false);
}

void KAModelSettingDialog::switchButtonStateEditing1()
{
    if (d_ptr->passwordEditApi->text().length() == 0){
        d_ptr->passwordEditApi->setEchoModeBtnVisible(true);
    }
    switchButtonState();
}

void KAModelSettingDialog::switchButtonStateEditing2()
{
    if (d_ptr->passwordEditSecret->text().length() == 0){
        d_ptr->passwordEditSecret->setEchoModeBtnVisible(true);
    }
    switchButtonState();
}
