<?php

declare(strict_types=0);
/**
 * vim:set softtabstop=4 shiftwidth=4 expandtab:
 *
 * LICENSE: GNU Affero General Public License, version 3 (AGPL-3.0-or-later)
 * Copyright Ampache.org, 2001-2024
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 */

namespace Ampache\Module\Api;

use Ampache\Module\Authorization\Access;
use Ampache\Module\Authorization\AccessLevelEnum;
use Ampache\Module\Authorization\AccessTypeEnum;

/**
 * API Class
 *
 * This handles functions relating to the API written for Ampache, initially
 * this is very focused on providing functionality for Amarok so it can
 * integrate with Ampache.
 *
 */
class Api4
{
    /**
     * This dict contains all known api-methods (key) and their respective handler (value)
     *
     * @var array<string, class-string<object>>
     */
    public const METHOD_LIST = [
        'advanced_search' => Method\Api4\AdvancedSearch4Method::class,
        'album' => Method\Api4\Album4Method::class,
        'albums' => Method\Api4\Albums4Method::class,
        'album_songs' => Method\Api4\AlbumSongs4Method::class,
        'artist' => Method\Api4\Artist4Method::class,
        'artists' => Method\Api4\Artists4Method::class,
        'artist_albums' => Method\Api4\ArtistAlbums4Method::class,
        'artist_songs' => Method\Api4\ArtistSongs4Method::class,
        'catalog' => Method\Api4\Catalog4Method::class,
        'catalogs' => Method\Api4\Catalogs4Method::class,
        'catalog_action' => Method\Api4\CatalogAction4Method::class,
        'catalog_file' => Method\Api4\CatalogFile4Method::class,
        'democratic' => Method\Api4\Democratic4Method::class,
        'download' => Method\Api4\Download4Method::class,
        'flag' => Method\Api4\Flag4Method::class,
        'followers' => Method\Api4\Followers4Method::class,
        'following' => Method\Api4\Following4Method::class,
        'friends_timeline' => Method\Api4\FriendsTimeline4Method::class,
        'get_art' => Method\Api4\GetArt4Method::class,
        'get_indexes' => Method\Api4\GetIndexes4Method::class,
        'get_similar' => Method\Api4\GetSimilar4Method::class,
        'goodbye' => Method\Api4\Goodbye4Method::class,
        'handshake' => Method\Api4\Handshake4Method::class,
        'last_shouts' => Method\Api4\LastShouts4Method::class,
        'license' => Method\Api4\License4Method::class,
        'licenses' => Method\Api4\Licenses4Method::class,
        'license_songs' => Method\Api4\LicenseSongs4Method::class,
        'localplay' => Method\Api4\Localplay4Method::class,
        'ping' => Method\Api4\Ping4Method::class,
        'playlist' => Method\Api4\Playlist4Method::class,
        'playlist_add_song' => Method\Api4\PlaylistAddSong4Method::class,
        'playlist_create' => Method\Api4\PlaylistCreate4Method::class,
        'playlist_delete' => Method\Api4\PlaylistDelete4Method::class,
        'playlist_edit' => Method\Api4\PlaylistEdit4Method::class,
        'playlist_generate' => Method\Api4\PlaylistGenerate4Method::class,
        'playlist_remove_song' => Method\Api4\PlaylistRemoveSong4Method::class,
        'playlist_songs' => Method\Api4\PlaylistSongs4Method::class,
        'playlists' => Method\Api4\Playlists4Method::class,
        'podcast' => Method\Api4\Podcast4Method::class,
        'podcasts' => Method\Api4\Podcasts4Method::class,
        'podcast_create' => Method\Api4\PodcastCreate4Method::class,
        'podcast_delete' => Method\Api4\PodcastDelete4Method::class,
        'podcast_edit' => Method\Api4\PodcastEdit4Method::class,
        'podcast_episode' => Method\Api4\PodcastEpisode4Method::class,
        'podcast_episodes' => Method\Api4\PodcastEpisodes4Method::class,
        'podcast_episode_delete' => Method\Api4\PodcastEpisodeDelete4Method::class,
        'rate' => Method\Api4\Rate4Method::class,
        'record_play' => Method\Api4\RecordPlay4Method::class,
        'scrobble' => Method\Api4\Scrobble4Method::class,
        'search' => Method\Api4\Search4Method::class,
        'search_songs' => Method\Api4\SearchSongs4Method::class,
        'share' => Method\Api4\Share4Method::class,
        'shares' => Method\Api4\Shares4Method::class,
        'share_create' => Method\Api4\ShareCreate4Method::class,
        'share_delete' => Method\Api4\ShareDelete4Method::class,
        'share_edit' => Method\Api4\ShareEdit4Method::class,
        'song' => Method\Api4\Song4Method::class,
        'songs' => Method\Api4\Songs4Method::class,
        'stats' => Method\Api4\Stats4Method::class,
        'stream' => Method\Api4\Stream4Method::class,
        'tag' => Method\Api4\Tag4Method::class,
        'tags' => Method\Api4\Tags4Method::class,
        'tag_albums' => Method\Api4\TagAlbums4Method::class,
        'tag_artists' => Method\Api4\TagArtists4Method::class,
        'tag_songs' => Method\Api4\TagSongs4Method::class,
        'genre' => Method\Api4\Genre4Method::class,
        'genres' => Method\Api4\Genres4Method::class,
        'genre_albums' => Method\Api4\GenreAlbums4Method::class,
        'genre_artists' => Method\Api4\GenreArtists4Method::class,
        'genre_songs' => Method\Api4\GenreSongs4Method::class,
        'timeline' => Method\Api4\Timeline4Method::class,
        'toggle_follow' => Method\Api4\ToggleFollow4Method::class,
        'update_art' => Method\Api4\UpdateArt4Method::class,
        'update_artist_info' => Method\Api4\UpdateArtistInfo4Method::class,
        'update_from_tags' => Method\Api4\UpdateFromTags4Method::class,
        'update_podcast' => Method\Api4\UpdatePodcast4Method::class,
        'url_to_song' => Method\Api4\UrlToSong4Method::class,
        'user' => Method\Api4\User4Method::class,
        'users' => Method\Api4\Users4Method::class,
        'user_create' => Method\Api4\UserCreate4Method::class,
        'user_delete' => Method\Api4\UserDelete4Method::class,
        'user_update' => Method\Api4\UserUpdate4Method::class,
        'video' => Method\Api4\Video4Method::class,
        'videos' => Method\Api4\Videos4Method::class,
    ];

    public static string $auth_version = '350001';
    public static string $version      = '443000'; // AMPACHE_VERSION

    /**
     * constructor
     * This really isn't anything to do here, so it's private
     */
    private function __construct()
    {
        // Rien a faire
    }

    /**
     * message
     * call the correct error / success message depending on format
     */
    public static function message(string $type, string $message, ?string $error_code = null, string $format = 'xml'): void
    {
        if ($type === 'error') {
            switch ($format) {
                case 'json':
                    echo Json4_Data::error($error_code ?? '400', $message);
                    break;
                default:
                    echo Xml4_Data::error($error_code ?? '400', $message);
            }
        }
        if ($type === 'success') {
            switch ($format) {
                case 'json':
                    echo Json4_Data::success($message);
                    break;
                default:
                    echo Xml4_Data::success($message);
            }
        }
    }

    /**
     * check_parameter
     *
     * This function checks the $input actually has the parameter.
     * Parameters must be an array of required elements as a string
     *
     * @param array<string, mixed> $input
     * @param string[] $parameters e.g. array('auth', type')
     * @param string $method
     * @return bool
     */
    public static function check_parameter(array $input, array $parameters, string $method = ''): bool
    {
        $parameter = Api::parameter_exists($input, $parameters);
        if ($parameter === true) {
            return true;
        }

        debug_event(self::class, "'" . $parameter . "' required on " . $method . " function call.", 2);
        self::message('error', T_('Missing mandatory parameter') . " '" . $parameter . "'", '401', $input['api_format']);

        return false;
    }

    /**
     * check_access
     *
     * This function checks the user can perform the function requested
     * 'interface', 100, $user->id
     */
    public static function check_access(AccessTypeEnum $type, AccessLevelEnum $level, int $user_id, string $method = '', string $format = 'xml'): bool
    {
        if (!Access::check($type, $level, $user_id)) {
            debug_event(self::class, $type->value . " '" . $level->value . "' required on " . $method . " function call.", 2);
            Api4::message('error', 'User does not have access to this function', '400', $format);

            return false;
        }

        return true;
    }
}
