#include <QtWidgets>
#include "vnewfiledialog.h"
#include "vconfigmanager.h"
#include "vdirectory.h"
#include "vmetawordlineedit.h"
#include "utils/vutils.h"
#include "utils/vmetawordmanager.h"
#include "utils/viconutils.h"

extern VConfigManager *g_config;

extern VMetaWordManager *g_mwMgr;

QString VNewFileDialog::s_lastTemplateFile;


VNewFileDialog::VNewFileDialog(const QString &p_title,
                               const QString &p_info,
                               const QString &p_defaultName,
                               VDirectory *p_directory,
                               QWidget *p_parent)
    : QDialog(p_parent),
      m_currentTemplateType(DocType::Unknown),
      m_directory(p_directory)
{
    setupUI(p_title, p_info, p_defaultName);

    connect(m_nameEdit, &VMetaWordLineEdit::textChanged, this, &VNewFileDialog::handleInputChanged);

    connect(m_templateCB, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
            this, &VNewFileDialog::handleCurrentTemplateChanged);

    handleInputChanged();

    tryToSelectLastTemplate();
}

void VNewFileDialog::setupUI(const QString &p_title,
                             const QString &p_info,
                             const QString &p_defaultName)
{
    QLabel *infoLabel = NULL;
    if (!p_info.isEmpty()) {
        infoLabel = new QLabel(p_info);
    }

    // Name.
    m_nameEdit = new VMetaWordLineEdit(p_defaultName);
    QValidator *validator = new QRegExpValidator(QRegExp(VUtils::c_fileNameRegExp),
                                                 m_nameEdit);
    m_nameEdit->setValidator(validator);
    int dotIndex = p_defaultName.lastIndexOf('.');
    m_nameEdit->setSelection(0, (dotIndex == -1) ? p_defaultName.size() : dotIndex);

    // Template.
    m_templateCB = VUtils::getComboBox();
    m_templateCB->setToolTip(tr("Choose a template (magic word supported)"));
    m_templateCB->setSizeAdjustPolicy(QComboBox::AdjustToContents);

    QPushButton *templateBtn = new QPushButton(VIconUtils::buttonIcon(":/resources/icons/manage_template.svg"),
                                               "");
    templateBtn->setToolTip(tr("Manage Templates"));
    templateBtn->setProperty("FlatBtn", true);
    connect(templateBtn, &QPushButton::clicked,
            this, []() {
                QUrl url = QUrl::fromLocalFile(g_config->getTemplateConfigFolder());
                QDesktopServices::openUrl(url);
            });

    QHBoxLayout *tempBtnLayout = new QHBoxLayout();
    tempBtnLayout->addWidget(m_templateCB);
    tempBtnLayout->addWidget(templateBtn);
    tempBtnLayout->addStretch();

    m_templateEdit = new QTextEdit();
    m_templateEdit->setReadOnly(true);

    QVBoxLayout *templateLayout = new QVBoxLayout();
    templateLayout->addLayout(tempBtnLayout);
    templateLayout->addWidget(m_templateEdit);

    m_templateEdit->hide();

    // InsertTitle.
    m_insertTitleCB = new QCheckBox(tr("Insert note name as title (for Markdown only)"));
    m_insertTitleCB->setToolTip(tr("Insert note name into the new note as a title"));
    m_insertTitleCB->setChecked(g_config->getInsertTitleFromNoteName());
    connect(m_insertTitleCB, &QCheckBox::stateChanged,
            this, [](int p_state) {
                g_config->setInsertTitleFromNoteName(p_state == Qt::Checked);
            });

    QFormLayout *topLayout = new QFormLayout();
    topLayout->addRow(tr("Note &name:"), m_nameEdit);
    topLayout->addWidget(m_insertTitleCB);
    topLayout->addRow(tr("Template:"), templateLayout);

    m_nameEdit->setMinimumWidth(m_insertTitleCB->sizeHint().width());

    m_warnLabel = new QLabel();
    m_warnLabel->setWordWrap(true);
    m_warnLabel->hide();

    // Ok is the default button.
    m_btnBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
    connect(m_btnBox, &QDialogButtonBox::accepted,
            this, [this]() {
                s_lastTemplateFile = m_templateCB->currentData().toString();
                QDialog::accept();
            });
    connect(m_btnBox, &QDialogButtonBox::rejected, this, &QDialog::reject);

    QPushButton *okBtn = m_btnBox->button(QDialogButtonBox::Ok);
    okBtn->setProperty("SpecialBtn", true);
    m_templateCB->setMaximumWidth(okBtn->sizeHint().width() * 4);

    QVBoxLayout *mainLayout = new QVBoxLayout();
    if (infoLabel) {
        mainLayout->addWidget(infoLabel);
    }

    mainLayout->addLayout(topLayout);
    mainLayout->addWidget(m_warnLabel);
    mainLayout->addWidget(m_btnBox);
    mainLayout->setSizeConstraint(QLayout::SetFixedSize);
    setLayout(mainLayout);

    setWindowTitle(p_title);
}

void VNewFileDialog::handleInputChanged()
{
    bool showWarnLabel = false;
    const QString name = m_nameEdit->getEvaluatedText();
    bool nameOk = !name.isEmpty();
    if (nameOk) {
        // Check if the name conflicts with existing note name.
        // Case-insensitive when creating note.
        QString warnText;
        if (m_directory->findFile(name, false)) {
            nameOk = false;
            warnText = tr("<span style=\"%1\">WARNING</span>: "
                          "Name (case-insensitive) <span style=\"%2\">%3</span> already exists. "
                          "Please choose another name.")
                         .arg(g_config->c_warningTextStyle)
                         .arg(g_config->c_dataTextStyle)
                         .arg(name);
        } else if (!VUtils::checkFileNameLegal(name)) {
            // Check if evaluated name contains illegal characters.
            nameOk = false;
            warnText = tr("<span style=\"%1\">WARNING</span>: "
                          "Name <span style=\"%2\">%3</span> contains illegal characters "
                          "(after magic word evaluation).")
                         .arg(g_config->c_warningTextStyle)
                         .arg(g_config->c_dataTextStyle)
                         .arg(name);
        }

        if (!nameOk) {
            showWarnLabel = true;
            m_warnLabel->setText(warnText);
        }
    }

    m_warnLabel->setVisible(showWarnLabel);

    QPushButton *okBtn = m_btnBox->button(QDialogButtonBox::Ok);
    okBtn->setEnabled(nameOk);

    if (nameOk) {
        updateTemplates(VUtils::docTypeFromName(name));
    }
}

QString VNewFileDialog::getNameInput() const
{
    return m_nameEdit->getEvaluatedText();
}

bool VNewFileDialog::getInsertTitleInput() const
{
    return m_insertTitleCB->isEnabled() && m_insertTitleCB->isChecked();
}

void VNewFileDialog::updateTemplates(DocType p_type)
{
    if (m_currentTemplateType == p_type) {
        return;
    }

    m_currentTemplateType = p_type;

    // Clear the combo.
    m_templateCB->clear();

    // Add None item.
    m_templateCB->addItem(tr("None"), "None");

    if (m_currentTemplateType == DocType::Unknown) {
        return;
    }

    int idx = 1;
    auto templates = g_config->getNoteTemplates(m_currentTemplateType);
    for (auto const & tp : templates) {
        m_templateCB->addItem(tp, tp);
        m_templateCB->setItemData(idx++, tp, Qt::ToolTipRole);
    }
}

void VNewFileDialog::handleCurrentTemplateChanged(int p_idx)
{
    if (p_idx == -1) {
        m_templateEdit->hide();
        enableInsertTitleCB(false);
        return;
    }

    QString file = m_templateCB->itemData(p_idx).toString();
    if (file == "None") {
        m_templateEdit->hide();
        enableInsertTitleCB(false);
        return;
    }

    // Read the template file.
    QString filePath = QDir(g_config->getTemplateConfigFolder()).filePath(file);
    m_template = VUtils::readFileFromDisk(filePath);
    DocType type = VUtils::docTypeFromName(file);
    switch (type) {
    case DocType::Html:
        m_templateEdit->setHtml(m_template);
        break;

    case DocType::Markdown:
        m_templateEdit->setPlainText(m_template);
        break;

    default:
        m_templateEdit->setPlainText(m_template);
        break;
    }

    m_templateEdit->show();
    enableInsertTitleCB(true);
}

void VNewFileDialog::enableInsertTitleCB(bool p_hasTemplate)
{
    m_insertTitleCB->setEnabled(!p_hasTemplate
                                && VUtils::docTypeFromName(m_nameEdit->getEvaluatedText())
                                   == DocType::Markdown);
}

bool VNewFileDialog::isTemplateUsed() const
{
    QString file = m_templateCB->currentData().toString();
    return !(file.isEmpty() || file == "None");
}

QString VNewFileDialog::getTemplate() const
{
    QString name = m_nameEdit->getEvaluatedText();
    QHash<QString, QString> overriddenTable;
    overriddenTable.insert("note", name);
    overriddenTable.insert("no", QFileInfo(name).completeBaseName());
    return g_mwMgr->evaluate(m_template, overriddenTable);
}

void VNewFileDialog::tryToSelectLastTemplate()
{
    Q_ASSERT(m_templateCB->count() > 0
             && m_templateCB->itemData(0).toString() == "None");
    if (s_lastTemplateFile.isEmpty() || s_lastTemplateFile == "None") {
        m_templateCB->setCurrentIndex(0);
        return;
    }

    int idx = m_templateCB->findData(s_lastTemplateFile);
    if (idx != -1) {
        m_templateCB->setCurrentIndex(idx);
    } else {
        s_lastTemplateFile.clear();
    }
}
