/* ArtistTest.cpp
 *
 * Copyright (C) 2011-2024 Michael Lugmair
 *
 * 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/>.
 */

#include "test/Common/SayonaraTest.h"
#include "test/Common/DatabaseUtils.h"

#include "Database/Connector.h"
#include "Database/Artists.h"
#include "Database/LibraryDatabase.h"
#include "Database/Library.h"
#include "Utils/MetaData/Artist.h"
#include "Utils/MetaData/MetaDataList.h"
#include "Utils/Algorithm.h"

namespace
{
	constexpr const LibraryId testLibraryId = 0;

	struct MetaDataBlock
	{
		QString album;
		QString artist;
		QString albumArtist;
		QString title;
	};

	[[maybe_unused]] MetaData createTestTrack(const MetaDataBlock& data)
	{
		auto track = MetaData{};
		track.setTitle(data.title);
		track.setAlbum(data.album);
		track.setArtist(data.artist);
		track.setAlbumArtist(data.albumArtist);

		const auto path = QString("/path/to/%1/%2/%3.mp3")
		                  .arg(data.artist)
		                  .arg(data.album)
		                  .arg(data.title);
		track.setFilepath(path);

		return track;
	}

	void cleanLibraryDatabase(DB::LibraryDatabase* db)
	{
		const auto tracks = db->getAllTracks();
		auto ids = IdList{};
		Util::Algorithm::transform(tracks, ids, [](const auto& track) {
			return track.id();
		});

		Test::DB::clearDatabase(db);
	}

	void createLibraryDatabase()
	{
		auto* dbConnector = DB::Connector::instance();
		dbConnector->deleteLibraryDatabase(testLibraryId);
		dbConnector->registerLibraryDatabase(testLibraryId);

		auto* db = dbConnector->libraryDatabase(testLibraryId);
		cleanLibraryDatabase(db);
	}

	void createTestLibrary(const QList<MetaDataBlock>& data)
	{
		createLibraryDatabase();
		auto* db = DB::Connector::instance()->libraryDatabase(testLibraryId);

		auto tracks = MetaDataList{};
		Util::Algorithm::transform(data, tracks, [&](const auto& dataItem) {
			return createTestTrack(dataItem);
		});

		db->storeMetadata(tracks);

		QVERIFY(db->getNumTracks() == data.count());
	}
}

class ArtistTest :
	public Test::Base
{
		Q_OBJECT

	public:
		ArtistTest() :
			Test::Base("ArtistTest") {}

		~ArtistTest() override = default;

	private slots:
		[[maybe_unused]] void testFetch();
		[[maybe_unused]] void testDelete();
};

[[maybe_unused]] void ArtistTest::testFetch() // NOLINT(readability-convert-member-functions-to-static)
{
	struct TestCase
	{
		bool alsoEmpty;
		bool onlyAlbumArtists;
		int expectedCount;
	};

	const auto testLibrary = QList<MetaDataBlock>{
		{"album1", "artist1", "albumArtist1", "title1"},
		{"album2", "artist1 feat. Dude", "albumArtist1", "title2"},
		{"album3", "artist3", "albumArtist3", "title3"}
	};

	constexpr auto testCases = std::array{
		TestCase{true, true, 6}, // albumArtist1, albumARtist3
		TestCase{true, false, 6}, // artist1, artist1 feat. Dude, artist3, albumArtist1, albumARtist3, orphan
		TestCase{false, true, 2}, // albumArtist1, albumARtist3
		TestCase{false, false, 5}, // artist1, artist1 feat. Dude, artist3, albumArtist1, albumARtist3, orphan
	};

	for(const auto& testCase: testCases)
	{
		createTestLibrary(testLibrary);

		auto* db = DB::Connector::instance()->libraryDatabase(testLibraryId);
		db->insertArtistIntoDatabase("Orphan");

		auto artists = db->getAllArtists(testCase.onlyAlbumArtists, testCase.alsoEmpty);
		QVERIFY(artists.count() == testCase.expectedCount);
	}
}

[[maybe_unused]] void ArtistTest::testDelete() // NOLINT(readability-convert-member-functions-to-static)
{
	createTestLibrary({
		{"album1", "artist1", "albumArtist1", "title1"},
		{"album2", "artist2", "albumArtist2", "title2"},
		{"album3", "artist3", "albumArtist3", "title3"}
	});

	auto* db = DB::Connector::instance()->libraryDatabase(testLibraryId);

	auto artists = db->getAllArtists(false, true);
	QVERIFY(artists.count() == 6);

	db->deleteArtist(db->getArtistID("artist1"));
	artists = db->getAllArtists(false, true);
	QVERIFY(artists.count() == 5);

	db->deleteArtist(db->getArtistID("artist1"));
	artists = db->getAllArtists(false, true);
	QVERIFY(artists.count() == 5);

	db->deleteArtist(db->getArtistID("albumArtist2"));
	artists = db->getAllArtists(false, true);
	QVERIFY(artists.count() == 4);

	db->deleteArtist(db->getArtistID("albumArtist3"));
	artists = db->getAllArtists(false, true);
	QVERIFY(artists.count() == 3);
}

QTEST_GUILESS_MAIN(ArtistTest)

#include "ArtistTest.moc"
