/*
 * 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/>.
 *
 */

#pragma once

#include "fileopsdefs.h"

#include <core/scripting/scriptparser.h>
#include <utils/worker.h>

#include <QDir>

#include <deque>
#include <set>
#include <unordered_map>

namespace Fooyin {
class AudioLoader;
class MusicLibrary;
class SettingsManager;

namespace FileOps {
struct FileOpsItem
{
    Operation op;
    QString name;
    QString source;
    QString destination;
    QString archivePath;
    QString archiveEntry;

    [[nodiscard]] QString displayName() const
    {
        return !name.isEmpty() ? name : source;
    }

    [[nodiscard]] QString displayDestination() const
    {
        return op == Operation::Rename ? QFileInfo{destination}.fileName() : destination;
    }
};
using FileOperations = std::deque<FileOpsItem>;

class FileOpsWorker : public Worker
{
    Q_OBJECT

public:
    FileOpsWorker(MusicLibrary* library, std::shared_ptr<AudioLoader> audioLoader, TrackList tracks,
                  SettingsManager* settings, QObject* parent = nullptr);

    void simulate(const FileOpPreset& preset);
    void run();
    void deleteFiles();

Q_SIGNALS:
    void simulated(const Fooyin::FileOps::FileOperations& operations);
    void deleteFinished(const Fooyin::TrackList& deletedTracks);
    void operationFinished(const Fooyin::FileOps::FileOpsItem& operation);

private:
    bool prepareOperations(const FileOpPreset& preset, bool emitSimulation);
    bool populateTrackPaths();

    void simulateMove();
    void simulateCopy();
    void simulateExtract();
    void simulateRename();

    [[nodiscard]] QString evaluatePath(const ParsedScript& script, const Track& track);

    bool renameFile(const FileOpsItem& item);
    static bool copyFile(const FileOpsItem& item);
    bool extractFile(const FileOpsItem& item);
    bool removeArchive(const FileOpsItem& item);

    void createDir(const QDir& dir);
    void removeDir(const QDir& dir);

    void reset();

    void updateExtractedArchiveTracks(const QString& archivePath);
    void handleEmptyDirs(const QDir& dir, const QString& filepath);
    void addEmptyDirs(const QDir& dir);
    void removeEmptyFoldersUpToLibraryRoot(const QString& filePath, int libraryId = -1);
    [[nodiscard]] QString libraryRootForDeletedPath(const QString& filePath, int libraryId) const;
    [[nodiscard]] int archiveLibraryId(const QString& archivePath) const;

    MusicLibrary* m_library;
    std::shared_ptr<AudioLoader> m_audioLoader;
    SettingsManager* m_settings;
    ScriptParser m_scriptParser;
    TrackList m_tracks;
    std::unordered_multimap<QString, Track> m_trackPaths;
    FileOpPreset m_preset;
    std::deque<FileOpsItem> m_operations;

    bool m_isMonitoring;
    std::optional<QDir> m_currentDir;
    std::set<QString> m_tracksProcessed;
    std::set<QString> m_filesToMove;
    std::set<QString> m_dirsToCreate;
    std::set<QString> m_dirsToRemove;
    std::set<QString> m_failedArchives;
    std::set<QString> m_successfulArchives;
    std::unordered_map<QString, QString> m_extractedTrackDestinations;
    TrackList m_tracksToUpdate;
    TrackList m_tracksToDelete;
};
} // namespace FileOps
} // namespace Fooyin
