#include "DuplicatedUploadChecker.h"

#include "DuplicatedNodeDialog.h"
#include "MegaApplication.h"
#include "Preferences.h"
#include "ServiceUrls.h"

#include <QDir>
#include <QFileInfo>

///BASE
///
void DuplicatedUploadBase::onNodeItemSelected()
{
    if(auto nodeItem = dynamic_cast<DuplicatedNodeItem*>(sender()))
    {
        mUploadInfo->setSolution(nodeItem->getType());
        emit selectionDone();
    }
}

QStringList& DuplicatedUploadBase::getCheckedNames(mega::MegaHandle parentHandle)
{
    return checkedNamesByParent[parentHandle];
}

QString DuplicatedUploadBase::getHeader(std::shared_ptr<DuplicatedNodeInfo> conflict)
{
    return conflict->conflictNodeIsFile() ? DuplicatedNodeDialog::tr("A file named [A] already exists at this destination")
           : DuplicatedNodeDialog::tr("A folder named [A] already exists at this destination");
}

QString DuplicatedUploadBase::getSkipText(bool isFile)
{
    return isFile ? DuplicatedNodeDialog::tr("The file at this destination will be maintained.")
           : DuplicatedNodeDialog::tr("The folder at this destination will be maintained.");
}

////FILE
void DuplicatedUploadFile::fillUi(DuplicatedNodeDialog *dialog, std::shared_ptr<DuplicatedNodeInfo> conflict)
{
    mUploadInfo = conflict;

    dialog->setHeader(getHeader(conflict),QString::fromUtf8(conflict->getConflictNode()->getName()));

    auto fileVersioningDisabled(Preferences::instance()->fileVersioningDisabled());

    if(!conflict->haveDifferentType() && !conflict->isNameConflict())
    {
        DuplicatedLocalItem* uploadItem = new DuplicatedLocalItem(dialog);

        if(fileVersioningDisabled)
        {
            uploadItem->setInfo(conflict, NodeItemType::FILE_UPLOAD_AND_REPLACE);
            QString description = DuplicatedNodeDialog::tr("The file at this destination will be replaced with the new file.");
            uploadItem->setDescription(description);
        }
        else
        {
            uploadItem->setInfo(conflict, NodeItemType::FILE_UPLOAD_AND_UPDATE);
            uploadItem->setDescription(DuplicatedNodeDialog::tr(
                "The file at this destination will be updated if the new file is different."));
            uploadItem->showLearnMore(ServiceUrls::getFileVersionHistoryHelpUrl().toString());
        }

        connect(uploadItem, &DuplicatedNodeItem::actionClicked, this, &DuplicatedUploadFile::onNodeItemSelected);
        dialog->addNodeItem(uploadItem);
    }

    //Upload and merge item
    DuplicatedRenameItem* uploadAndRename = new DuplicatedRenameItem(dialog);
    uploadAndRename->setRenameInfo(conflict);
    uploadAndRename->setDescription(DuplicatedNodeDialog::tr("The file will be renamed as:"));
    connect(uploadAndRename, &DuplicatedNodeItem::actionClicked, this, &DuplicatedUploadFile::onNodeItemSelected);
    dialog->addNodeItem(uploadAndRename);

    DuplicatedRemoteItem* dontUploadItem = new DuplicatedRemoteItem(dialog);
    dontUploadItem->setInfo(conflict, NodeItemType::DONT_UPLOAD);
    dontUploadItem->setDescription(getSkipText(conflict->conflictNodeIsFile()));
    connect(dontUploadItem, &DuplicatedNodeItem::actionClicked, this, &DuplicatedUploadFile::onNodeItemSelected);
    dialog->addNodeItem(dontUploadItem);
}

///FOLDER
void DuplicatedUploadFolder::fillUi(DuplicatedNodeDialog* dialog, std::shared_ptr<DuplicatedNodeInfo> conflict)
{
    mUploadInfo = conflict;

    dialog->setHeader(getHeader(conflict),QString::fromUtf8(conflict->getConflictNode()->getName()));

    if(!conflict->haveDifferentType())
    {
        //Upload and merge item
        DuplicatedLocalItem* uploadAndMergeItem = new DuplicatedLocalItem(dialog);
        uploadAndMergeItem->setInfo(conflict, NodeItemType::FOLDER_UPLOAD_AND_MERGE);
        uploadAndMergeItem->setDescription(DuplicatedNodeDialog::tr("The new folder will be merged with the folder at this destination."));
        connect(uploadAndMergeItem, &DuplicatedNodeItem::actionClicked, this, &DuplicatedUploadFolder::onUploadAndMergeSelected);
        dialog->addNodeItem(uploadAndMergeItem);
    }

    DuplicatedRemoteItem* dontUploadItem = new DuplicatedRemoteItem(dialog);
    dontUploadItem->setInfo(conflict, NodeItemType::DONT_UPLOAD);
    dontUploadItem->setDescription(getSkipText(conflict->conflictNodeIsFile()));
    connect(dontUploadItem, &DuplicatedNodeItem::actionClicked, this, &DuplicatedUploadFolder::onNodeItemSelected);
    dialog->addNodeItem(dontUploadItem);
}

void DuplicatedUploadFolder::onUploadAndMergeSelected()
{
    //This is done to merge the local folder into the remote one (we need to upload it with the remote name)
    if(mUploadInfo->isNameConflict())
    {
        mUploadInfo->setNewName(QString::fromUtf8(mUploadInfo->getConflictNode()->getName()));
    }

    DuplicatedUploadFolder::onNodeItemSelected();
}

void DuplicatedMoveFile::fillUi(DuplicatedNodeDialog *dialog, std::shared_ptr<DuplicatedNodeInfo> conflict)
{
    if(auto moveNodeInfo = std::dynamic_pointer_cast<DuplicatedMoveNodeInfo>(conflict))
    {
        mUploadInfo = conflict;

        dialog->setHeader(
            getHeader(conflict), QString::fromUtf8(conflict->getConflictNode()->getName()));

        // When copying a node into its own parent folder, the node conflicts with itself.
        // Replacing a file with itself is meaningless, so only offer rename/skip.
        const bool conflictsWithItself =
            moveNodeInfo->getSourceItemHandle() == conflict->getConflictNode()->getHandle();

        if (!conflict->haveDifferentType() && !conflictsWithItself)
        {
            DuplicatedRemoteItem* uploadItem = new DuplicatedRemoteItem(dialog);

            uploadItem->setInfoSpecifyingHandle(conflict, moveNodeInfo->getSourceItemHandle(), NodeItemType::FILE_UPLOAD_AND_REPLACE);
            QString description = DuplicatedNodeDialog::tr(
                "The file at this destination will be replaced with the new file.");
            uploadItem->setDescription(description);

            connect(uploadItem, &DuplicatedNodeItem::actionClicked, this, &DuplicatedMoveFile::onNodeItemSelected);
            dialog->addNodeItem(uploadItem);
        }

        //Upload and merge item
        DuplicatedRenameItem* uploadAndRename = new DuplicatedRenameItem(dialog);
        uploadAndRename->setRenameInfo(conflict);
        uploadAndRename->setDescription(DuplicatedNodeDialog::tr("The file will be renamed as:"));
        connect(uploadAndRename,
            &DuplicatedNodeItem::actionClicked,
            this,
            &DuplicatedMoveFile::onNodeItemSelected);
        dialog->addNodeItem(uploadAndRename);

        DuplicatedRemoteItem* dontUploadItem = new DuplicatedRemoteItem(dialog);
        dontUploadItem->setInfo(conflict, NodeItemType::DONT_UPLOAD);
        dontUploadItem->setDescription(getSkipText(conflict->conflictNodeIsFile()));
        connect(dontUploadItem,
            &DuplicatedNodeItem::actionClicked,
            this,
            &DuplicatedMoveFile::onNodeItemSelected);
        dialog->addNodeItem(dontUploadItem);
    }
}

///FOLDER
void DuplicatedMoveFolder::fillUi(DuplicatedNodeDialog* dialog,  std::shared_ptr<DuplicatedNodeInfo> conflict)
{
    if(auto moveNodeInfo = std::dynamic_pointer_cast<DuplicatedMoveNodeInfo>(conflict))
    {
        mUploadInfo = conflict;

        dialog->setHeader(
            getHeader(conflict), QString::fromUtf8(conflict->getConflictNode()->getName()));

        if(!conflict->haveDifferentType())
        {
            //Upload and merge item
            DuplicatedRemoteItem* uploadAndMergeItem = new DuplicatedRemoteItem(dialog);
            uploadAndMergeItem->setInfoSpecifyingHandle(conflict, moveNodeInfo->getSourceItemHandle(), NodeItemType::FOLDER_UPLOAD_AND_MERGE);
            uploadAndMergeItem->setDescription(DuplicatedNodeDialog::tr(
                "The new folder will be merged with the folder at this destination."));
            connect(uploadAndMergeItem,
                &DuplicatedNodeItem::actionClicked,
                this,
                &DuplicatedMoveFolder::onNodeItemSelected);
            dialog->addNodeItem(uploadAndMergeItem);
        }

        // Move and rename item
        DuplicatedRenameItem* renameItem = new DuplicatedRenameItem(dialog);
        renameItem->setRenameInfo(conflict);
        renameItem->setDescription(DuplicatedNodeDialog::tr("The folder will be renamed as:"));
        connect(renameItem,
                &DuplicatedNodeItem::actionClicked,
                this,
                &DuplicatedMoveFolder::onNodeItemSelected);
        dialog->addNodeItem(renameItem);

        DuplicatedRemoteItem* dontUploadItem = new DuplicatedRemoteItem(dialog);
        dontUploadItem->setInfo(conflict, NodeItemType::DONT_UPLOAD);
        dontUploadItem->setDescription(getSkipText(conflict->conflictNodeIsFile()));
        connect(dontUploadItem,
            &DuplicatedNodeItem::actionClicked,
            this,
            &DuplicatedMoveFolder::onNodeItemSelected);
        dialog->addNodeItem(dontUploadItem);
    }
}
