/* LocalLibrary.h */

/* Copyright (C) 2011-2024 Michael Lugmair (Lucio Carreras)
 *
 * This file is part of sayonara player
 *
 * This program 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.

 * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef SAYONARA_PLAYER_LOCAL_LIBRARY_H
#define SAYONARA_PLAYER_LOCAL_LIBRARY_H

#include "Importer/LibraryImporter.h"
#include "Utils/Library/Filter.h"
#include "Utils/Library/LibraryNamespaces.h"
#include "Utils/Library/Sorting.h"
#include "Utils/Pimpl.h"

class LibraryPlaylistInteractor;

namespace DB
{
	class LibraryDatabase;
}

namespace Util
{
	class FileSystem;
}

namespace Library
{
	class Info;
	class Manager;
	class ReloadThread;
}

namespace Gui
{
	class ExtensionSet;
}

class LocalLibrary :
	public QObject
{
	friend class Library::Manager;

		Q_OBJECT
		PIMPL(LocalLibrary)
	signals:
		void sigAllTracksLoaded();
		void sigAllAlbumsLoaded();
		void sigAllArtistsLoaded();

		void sigReloadingLibrary(const QString& message, int progress);
		void sigReloadingLibraryFinished();

		void sigDeleteAnswer(QString);

		void sigCurrentAlbumChanged(int row);
		void sigCurrentTrackChanged(int row);
		void sigImportDialogRequested(const QString& targetDirectory);
		void sigRenamed(const QString& newName);
		void sigPathChanged(const QString& newPath);

	public:
		LocalLibrary(Library::Manager* libraryManager, LibraryId id, DB::LibraryDatabase* libraryDatabase, LibraryPlaylistInteractor* playlistInteractor,
		             const std::shared_ptr<Util::FileSystem>& fileSystem, QObject* parent = nullptr);
		~LocalLibrary() override;

		void init();
		[[nodiscard]] bool isLoaded() const;

		bool setLibraryPath(const QString& libraryPath) const;
		bool setLibraryName(const QString& libraryName) const;

		[[nodiscard]] const MetaDataList& tracks() const;
		[[nodiscard]] const AlbumList& albums() const;
		[[nodiscard]] const ArtistList& artists() const;
		[[nodiscard]] const MetaDataList& currentTracks() const;

		[[nodiscard]] const Util::Set<AlbumId>& selectedAlbums() const;
		[[nodiscard]] const Util::Set<ArtistId>& selectedArtists() const;

		[[nodiscard]] Gui::ExtensionSet extensions() const;
		void setExtensions(const Gui::ExtensionSet& extensions);

		[[nodiscard]] Library::Sortings sortorder() const;
		[[nodiscard]] Library::Filter filter() const;
		void changeFilter(Library::Filter, bool force = false);
		void changeCurrentDisc(Disc disc);

		[[nodiscard]] Library::Info info() const;
		[[nodiscard]] bool isEmpty() const;
		[[nodiscard]] bool isReloading() const;

		[[nodiscard]] LibraryPlaylistInteractor* playlistInteractor() const;
		[[nodiscard]] Library::Importer* importer();

	public slots: // NOLINT(readability-redundant-access-specifiers)
		void deleteTracks(const MetaDataList& tracks, Library::TrackDeletionMode mode);
		void reloadLibrary(bool clear_first, Library::ReloadQuality quality);
		void importFiles(const QStringList& files);
		void importFilesTo(const QStringList& files, const QString& targetDirectory);

		void refetch();
		void refreshCurrentView();

		void findTrack(TrackID id);

		void selectedArtistsChanged(const IndexSet& indexes);
		void selectedAlbumsChanged(const IndexSet& indexes, bool ignore_artists = false);
		void selectedTracksChanged(const IndexSet& indexes);

		void fetchByFilter(const Library::Filter& filter, bool force);
		void fetchTracksByPath(const QStringList& paths);

		void deleteFetchedTracks(Library::TrackDeletionMode mode);
		void deleteCurrentTracks(Library::TrackDeletionMode mode);
		void deleteAllTracks();

		void changeTrackSortorder(Library::TrackSortorder sortOrder);
		void changeAlbumSortorder(Library::AlbumSortorder sortOrder);
		void changeArtistSortorder(Library::ArtistSortorder sortOrder);

	private:
		void changeTrackSelection(const IndexSet& indexes);
		void changeArtistSelection(const IndexSet& indexes);
		void changeAlbumSelection(const IndexSet& indexes, bool ignore_artists = false);
		void emitAll();

		void replaceAlbum(int index, const Album& album);
		void replaceTrack(int index, const MetaData& track);

		void prepareTracks();
		void prepareAlbums();
		void prepareArtists();

		void initConnections();
		void initReloadThread();

		[[nodiscard]] ArtistList getAllArtists() const;
		[[nodiscard]] ArtistList getAllArtistsBySearchstring(const Library::Filter& filter) const;

		[[nodiscard]] AlbumList getAllAlbums() const;
		[[nodiscard]] AlbumList
		getAllAlbumsByArtist(const IdList& artistIds, const Library::Filter& filter) const;
		[[nodiscard]] AlbumList getAllAlbumsBySearchstring(const Library::Filter& filter) const;

		[[nodiscard]] int getTrackCount() const;
		[[nodiscard]] MetaDataList getAllTracks() const;
		[[nodiscard]] MetaDataList getAllTracks(const QStringList& paths) const;
		[[nodiscard]] MetaDataList
		getAllTracksByArtist(const IdList& artistIds, const Library::Filter& filter) const;
		[[nodiscard]] MetaDataList
		getAllTracksByAlbum(const IdList& albumIds, const Library::Filter& filter) const;
		[[nodiscard]] MetaDataList getAllTracksBySearchstring(const Library::Filter& filter) const;
		[[nodiscard]] MetaDataList getAllTracksByPath(const QStringList& paths) const;

		[[nodiscard]] MetaData getTrackById(TrackID trackId) const;
		[[nodiscard]] Album getAlbumById(AlbumId albumId) const;
		[[nodiscard]] Artist getArtistById(ArtistId artistId) const;

	private slots: // NOLINT(readability-redundant-access-specifiers)
		void reloadThreadFinished();
		void searchModeChanged();
		void showAlbumArtistsChanged();
		void importStatusChanged(Library::Importer::ImportStatus status);
		void metadataChanged();
		void albumsChanged();
};

#endif // SAYONARA_PLAYER_LOCAL_LIBRARY_H
