/*
 * Fooyin
 * Copyright © 2024, Luke Taylor <luket@pm.me>
 *
 * Fooyin is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Fooyin is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Fooyin.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include "artworkdownloadpage.h"

#include "artwork/artworkfinder.h"
#include "artwork/artworksaveutils.h"
#include "internalguisettings.h"

#include <gui/guiconstants.h>
#include <gui/iconloader.h>
#include <gui/widgets/scriptlineedit.h>
#include <utils/settings/settingsmanager.h>
#include <utils/utils.h>

#include <QButtonGroup>
#include <QComboBox>
#include <QFileDialog>
#include <QGridLayout>
#include <QGroupBox>
#include <QLabel>
#include <QMainWindow>
#include <QRadioButton>
#include <QSpinBox>
#include <QStackedWidget>

using namespace Qt::StringLiterals;

namespace Fooyin {
class ArtworkDownloadPageWidget : public SettingsPageWidget
{
    Q_OBJECT

public:
    explicit ArtworkDownloadPageWidget(SettingsManager* settings);

    void load() override;
    void apply() override;
    void reset() override;

private:
    void browseDestination(Track::Cover type) const;

    SettingsManager* m_settings;

    QComboBox* m_coverTypes;
    QStackedWidget* m_coverStack;
    QWidget* m_frontWidget;
    QWidget* m_backWidget;
    QWidget* m_artistWidget;

    struct CoverControls
    {
        QRadioButton* embedded;
        QRadioButton* directory;
        QLineEdit* path;
        ScriptLineEdit* filename;
        QComboBox* format;
        QLabel* qualityLabel;
        QSpinBox* quality;

        explicit CoverControls(QWidget* parent)
            : embedded{new QRadioButton(tr("Embed in file"), parent)}
            , directory{new QRadioButton(tr("Save to directory"), parent)}
            , path{new QLineEdit(parent)}
            , filename{new ScriptLineEdit(parent)}
            , format{new QComboBox(parent)}
            , qualityLabel{new QLabel(tr("Quality") + u":", parent)}
            , quality{new QSpinBox(parent)}
        { }
    };

    std::map<Track::Cover, CoverControls> m_typeControls;
};

ArtworkDownloadPageWidget::ArtworkDownloadPageWidget(SettingsManager* settings)
    : m_settings{settings}
    , m_coverTypes{new QComboBox(this)}
    , m_coverStack{new QStackedWidget(this)}
    , m_frontWidget{new QWidget(this)}
    , m_backWidget{new QWidget(this)}
    , m_artistWidget{new QWidget(this)}
{
    m_coverTypes->addItem(tr("Front Cover"));
    m_coverTypes->addItem(tr("Back Cover"));
    m_coverTypes->addItem(tr("Artist"));

    m_coverStack->addWidget(m_frontWidget);
    m_coverStack->addWidget(m_backWidget);
    m_coverStack->addWidget(m_artistWidget);

    int row{0};

    const auto addType = [this, &row](Track::Cover type, QWidget* widget) {
        auto* methodGroup  = new QGroupBox(tr("Save Method"), widget);
        auto* methodLayout = new QGridLayout(methodGroup);

        CoverControls& controls = m_typeControls.emplace(type, CoverControls{widget}).first->second;

        row = 0;
        methodLayout->addWidget(controls.embedded, row++, 0);
        methodLayout->addWidget(controls.directory, row++, 0);

        auto* formatGroup    = new QGroupBox(tr("Format"), widget);
        auto* formatLayout   = new QGridLayout(formatGroup);
        auto* locationGroup  = new QGroupBox(tr("Save Location"), widget);
        auto* locationLayout = new QGridLayout(locationGroup);

        auto* dirLabel      = new QLabel(tr("Directory") + u":", widget);
        auto* filenameLabel = new QLabel(tr("Filename") + u":", widget);
        auto* filetypeLabel = new QLabel(tr("File type") + u":", widget);

        controls.format->addItem(tr("Automatic"), QString{});
        for(const QString& format : supportedArtworkSaveFormats()) {
            controls.format->addItem(artworkSaveFormatLabel(format), format);
        }
        controls.quality->setRange(0, 100);
        controls.quality->setValue(90);

        row = 0;
        formatLayout->addWidget(filetypeLabel, row, 0);
        formatLayout->addWidget(controls.format, row++, 1);
        formatLayout->addWidget(controls.qualityLabel, row, 0);
        formatLayout->addWidget(controls.quality, row++, 1);
        formatLayout->setColumnStretch(3, 1);

        row = 0;
        locationLayout->addWidget(dirLabel, row, 0);
        locationLayout->addWidget(controls.path, row++, 1);
        locationLayout->addWidget(filenameLabel, row, 0);
        locationLayout->addWidget(controls.filename, row++, 1);

        auto* typeLayout = new QGridLayout(widget);

        row = 0;
        typeLayout->addWidget(methodGroup, row++, 0);
        typeLayout->addWidget(formatGroup, row++, 0);
        typeLayout->addWidget(locationGroup, row++, 0);

        auto* browseAction = new QAction(widget);
        Gui::setThemeIcon(browseAction, ::Fooyin::Constants::Icons::Options);
        QObject::connect(browseAction, &QAction::triggered, widget, [this, type]() { browseDestination(type); });
        controls.path->addAction(browseAction, QLineEdit::TrailingPosition);

        const auto updateFormatControls = [type, this]() {
            const auto& typeControls   = m_typeControls.at(type);
            const QString format       = typeControls.format->currentData().toString();
            const bool supportsQuality = (format == "jpeg"_L1 || format == "webp"_L1);
            typeControls.qualityLabel->setEnabled(supportsQuality);
            typeControls.quality->setEnabled(supportsQuality);
        };
        QObject::connect(controls.format, &QComboBox::currentIndexChanged, widget, updateFormatControls);
        updateFormatControls();
    };

    addType(Track::Cover::Front, m_frontWidget);
    addType(Track::Cover::Back, m_backWidget);
    addType(Track::Cover::Artist, m_artistWidget);

    auto* layout = new QGridLayout(this);

    row = 0;
    layout->addWidget(new QLabel(tr("Cover type") + u":"_s, this), row, 0);
    layout->addWidget(m_coverTypes, row++, 1);
    layout->addWidget(m_coverStack, row++, 0, 1, 3);
    layout->setColumnStretch(2, 1);
    layout->setRowStretch(layout->rowCount(), 1);

    QObject::connect(m_coverTypes, &QComboBox::currentIndexChanged, m_coverStack, &QStackedWidget::setCurrentIndex);
}

void ArtworkDownloadPageWidget::load()
{
    const auto saveMethods
        = m_settings->value<Settings::Gui::Internal::ArtworkSaveMethods>().value<ArtworkSaveMethods>();

    for(const auto& [type, controls] : m_typeControls) {
        const auto& coverMethod = saveMethods.value(type);
        controls.embedded->setChecked(coverMethod.method == ArtworkSaveMethod::Embedded);
        controls.directory->setChecked(coverMethod.method == ArtworkSaveMethod::Directory);
        controls.path->setText(coverMethod.dir);
        controls.filename->setText(coverMethod.filename);

        if(const int index = controls.format->findData(coverMethod.format); index >= 0) {
            controls.format->setCurrentIndex(index);
        }
        else {
            controls.format->setCurrentIndex(0);
        }
        controls.quality->setValue(coverMethod.quality);
    }
}

void ArtworkDownloadPageWidget::apply()
{
    ArtworkSaveMethods saveMethods;

    for(const auto& [type, controls] : m_typeControls) {
        auto& coverMethod = saveMethods[type];
        coverMethod.method
            = controls.embedded->isChecked() ? ArtworkSaveMethod::Embedded : ArtworkSaveMethod::Directory;
        coverMethod.dir      = controls.path->text();
        coverMethod.filename = controls.filename->text();
        coverMethod.format   = controls.format->currentData().toString();
        coverMethod.quality  = controls.quality->value();
    }

    m_settings->set<Settings::Gui::Internal::ArtworkSaveMethods>(QVariant::fromValue(saveMethods));
}

void ArtworkDownloadPageWidget::reset()
{
    m_settings->reset<Settings::Gui::Internal::ArtworkSaveMethods>();
    m_settings->reset<Settings::Gui::Internal::ArtworkAutoSearch>();
    m_settings->reset<Settings::Gui::Internal::ArtworkAlbumField>();
    m_settings->reset<Settings::Gui::Internal::ArtworkArtistField>();
    m_settings->reset<Settings::Gui::Internal::ArtworkMatchThreshold>();
}

void ArtworkDownloadPageWidget::browseDestination(Track::Cover type) const
{
    auto* lineEdit     = m_typeControls.at(type).path;
    const QString path = !lineEdit->text().isEmpty() ? lineEdit->text() : QDir::homePath();
    const QString dir  = QFileDialog::getExistingDirectory(Utils::getMainWindow(), tr("Select Directory"), path);
    if(!dir.isEmpty()) {
        lineEdit->setText(dir);
    }
}

ArtworkDownloadPage::ArtworkDownloadPage(SettingsManager* settings, QObject* parent)
    : SettingsPage{settings->settingsDialog(), parent}
{
    setId(Constants::Page::ArtworkDownload);
    setName(tr("Download"));
    setCategory({tr("Interface"), tr("Artwork")});
    setWidgetCreator([settings] { return new ArtworkDownloadPageWidget(settings); });
}
} // namespace Fooyin

#include "artworkdownloadpage.moc"
#include "moc_artworkdownloadpage.cpp"
