import { z } from 'zod';

export enum JFAlbumArtistListSort {
    ALBUM = 'Album,SortName',
    DURATION = 'Runtime,AlbumArtist,Album,SortName',
    NAME = 'SortName,Name',
    RANDOM = 'Random,SortName',
    RECENTLY_ADDED = 'DateCreated,SortName',
    RELEASE_DATE = 'PremiereDate,AlbumArtist,Album,SortName',
}

export enum JFAlbumListSort {
    ALBUM_ARTIST = 'AlbumArtist,SortName',
    COMMUNITY_RATING = 'CommunityRating,SortName',
    CRITIC_RATING = 'CriticRating,SortName',
    NAME = 'SortName',
    PLAY_COUNT = 'PlayCount',
    RANDOM = 'Random,SortName',
    RECENTLY_ADDED = 'DateCreated,SortName',
    RELEASE_DATE = 'ProductionYear,PremiereDate,SortName',
}

export enum JFArtistListSort {
    ALBUM = 'Album,SortName',
    DURATION = 'Runtime,AlbumArtist,Album,SortName',
    NAME = 'SortName,Name',
    RANDOM = 'Random,SortName',
    RECENTLY_ADDED = 'DateCreated,SortName',
    RELEASE_DATE = 'PremiereDate,AlbumArtist,Album,SortName',
}

export enum JFGenreListSort {
    NAME = 'SortName',
}

export enum JFPlaylistListSort {
    ALBUM_ARTIST = 'AlbumArtist,SortName',
    DURATION = 'Runtime',
    NAME = 'SortName',
    RECENTLY_ADDED = 'DateCreated,SortName',
    SONG_COUNT = 'ChildCount',
}

export enum JFSongListSort {
    ALBUM = 'Album,SortName',
    ALBUM_ARTIST = 'AlbumArtist,Album,SortName',
    ARTIST = 'Artist,Album,SortName',
    COMMUNITY_RATING = 'CommunityRating,SortName',
    DURATION = 'Runtime,AlbumArtist,Album,SortName',
    NAME = 'Name',
    PLAY_COUNT = 'PlayCount,SortName',
    RANDOM = 'Random,SortName',
    RECENTLY_ADDED = 'DateCreated,SortName',
    RECENTLY_PLAYED = 'DatePlayed,SortName',
    RELEASE_DATE = 'PremiereDate,AlbumArtist,Album,SortName',
}

export enum JFSortOrder {
    ASC = 'Ascending',
    DESC = 'Descending',
}

const sortOrderValues = ['Ascending', 'Descending'] as const;

const jfExternal = {
    IMDB: 'Imdb',
    MUSIC_BRAINZ: 'MusicBrainz',
    THE_AUDIO_DB: 'TheAudioDb',
    THE_MOVIE_DB: 'TheMovieDb',
    TVDB: 'Tvdb',
};

const jfImage = {
    BACKDROP: 'Backdrop',
    BANNER: 'Banner',
    BOX: 'Box',
    CHAPTER: 'Chapter',
    DISC: 'Disc',
    LOGO: 'Logo',
    PRIMARY: 'Primary',
    THUMB: 'Thumb',
} as const;

const jfCollection = {
    MUSIC: 'music',
    PLAYLISTS: 'playlists',
} as const;

const error = z.object({
    errors: z.object({
        recursive: z.array(z.string()),
    }),
    status: z.number(),
    title: z.string(),
    traceId: z.string(),
    type: z.string(),
});

const baseParameters = z.object({
    AlbumArtistIds: z.string().optional(),
    ArtistIds: z.string().optional(),
    ContributingArtistIds: z.string().optional(),
    EnableImageTypes: z.string().optional(),
    EnableTotalRecordCount: z.boolean().optional(),
    EnableUserData: z.boolean().optional(),
    EnableUserDataTypes: z.boolean().optional(),
    ExcludeArtistIds: z.string().optional(),
    ExcludeItemIds: z.string().optional(),
    ExcludeItemTypes: z.string().optional(),
    Fields: z.array(z.string()).readonly().optional(),
    FolderId: z.string().optional(),
    ImageTypeLimit: z.number().optional(),
    IncludeArtists: z.boolean().optional(),
    IncludeGenres: z.boolean().optional(),
    IncludeItemTypes: z.string().optional(),
    IncludeMedia: z.boolean().optional(),
    IncludePeople: z.boolean().optional(),
    IncludeStudios: z.boolean().optional(),
    IsFavorite: z.boolean().optional(),
    Limit: z.number().optional(),
    MediaTypes: z.string().optional(),
    NameStartsWith: z.string().optional(),
    ParentId: z.string().optional(),
    Recursive: z.boolean().optional(),
    SearchTerm: z.string().optional(),
    SortBy: z.string().optional(),
    SortOrder: z.enum(sortOrderValues).optional(),
    StartIndex: z.number().optional(),
    Tags: z.string().optional(),
    UserId: z.string().optional(),
    Years: z.string().optional(),
});

const paginationParameters = z.object({
    Limit: z.number().optional(),
    SortOrder: z.enum(sortOrderValues).optional(),
    StartIndex: z.number().optional(),
});

const pagination = z.object({
    StartIndex: z.number(),
    TotalRecordCount: z.number(),
});

const imageTags = z.object({
    Logo: z.string().optional(),
    Primary: z.string().optional(),
});

const imageBlurHashes = z.object({
    Backdrop: z.record(z.string(), z.string()).optional(),
    Logo: z.record(z.string(), z.string()).optional(),
    Primary: z.record(z.string(), z.string()).optional(),
});

const userData = z.object({
    IsFavorite: z.boolean(),
    Key: z.string(),
    PlaybackPositionTicks: z.number(),
    PlayCount: z.number(),
    Played: z.boolean(),
});

const externalUrl = z.object({
    Name: z.string(),
    Url: z.string(),
});

const mediaStream = z.object({
    AspectRatio: z.string().optional(),
    BitDepth: z.number().optional(),
    BitRate: z.number().optional(),
    ChannelLayout: z.string().optional(),
    Channels: z.number().optional(),
    Codec: z.string(),
    CodecTimeBase: z.string(),
    ColorSpace: z.string().optional(),
    Comment: z.string().optional(),
    DisplayTitle: z.string().optional(),
    Height: z.number().optional(),
    Index: z.number(),
    IsDefault: z.boolean(),
    IsExternal: z.boolean(),
    IsForced: z.boolean(),
    IsInterlaced: z.boolean(),
    IsTextSubtitleStream: z.boolean(),
    Level: z.number(),
    PixelFormat: z.string().optional(),
    Profile: z.string().optional(),
    RealFrameRate: z.number().optional(),
    RefFrames: z.number().optional(),
    SampleRate: z.number().optional(),
    SupportsExternalStream: z.boolean(),
    TimeBase: z.string(),
    Type: z.string(),
    Width: z.number().optional(),
});

const mediaSources = z.object({
    Bitrate: z.number(),
    Container: z.string(),
    DefaultAudioStreamIndex: z.number(),
    ETag: z.string(),
    Formats: z.array(z.any()),
    GenPtsInput: z.boolean(),
    Id: z.string(),
    IgnoreDts: z.boolean(),
    IgnoreIndex: z.boolean(),
    IsInfiniteStream: z.boolean(),
    IsRemote: z.boolean(),
    MediaAttachments: z.array(z.any()),
    MediaStreams: z.array(mediaStream),
    Name: z.string(),
    Path: z.string(),
    Protocol: z.string(),
    ReadAtNativeFramerate: z.boolean(),
    RequiredHttpHeaders: z.any(),
    RequiresClosing: z.boolean(),
    RequiresLooping: z.boolean(),
    RequiresOpening: z.boolean(),
    RunTimeTicks: z.number(),
    Size: z.number(),
    SupportsDirectPlay: z.boolean(),
    SupportsDirectStream: z.boolean(),
    SupportsProbing: z.boolean(),
    SupportsTranscoding: z.boolean(),
    Type: z.string(),
});

const sessionInfo = z.object({
    AdditionalUsers: z.array(z.any()),
    ApplicationVersion: z.string(),
    Capabilities: z.object({
        PlayableMediaTypes: z.array(z.any()),
        SupportedCommands: z.array(z.any()),
        SupportsContentUploading: z.boolean(),
        SupportsMediaControl: z.boolean(),
        SupportsPersistentIdentifier: z.boolean(),
        SupportsSync: z.boolean(),
    }),
    Client: z.string(),
    DeviceId: z.string(),
    DeviceName: z.string(),
    HasCustomDeviceName: z.boolean(),
    Id: z.string(),
    IsActive: z.boolean(),
    LastActivityDate: z.string(),
    LastPlaybackCheckIn: z.string(),
    NowPlayingQueue: z.array(z.any()),
    NowPlayingQueueFullItems: z.array(z.any()),
    PlayableMediaTypes: z.array(z.any()),
    PlayState: z.object({
        CanSeek: z.boolean(),
        IsMuted: z.boolean(),
        IsPaused: z.boolean(),
        PositionTicks: z.number().optional(),
        RepeatMode: z.string(),
    }),
    RemoteEndPoint: z.string(),
    ServerId: z.string(),
    SupportedCommands: z.array(z.any()),
    SupportsMediaControl: z.boolean(),
    SupportsRemoteControl: z.boolean(),
    UserId: z.string(),
    UserName: z.string(),
});

const configuration = z.object({
    DisplayCollectionsView: z.boolean(),
    DisplayMissingEpisodes: z.boolean(),
    EnableLocalPassword: z.boolean(),
    EnableNextEpisodeAutoPlay: z.boolean(),
    GroupedFolders: z.array(z.any()),
    HidePlayedInLatest: z.boolean(),
    LatestItemsExcludes: z.array(z.any()),
    MyMediaExcludes: z.array(z.any()),
    OrderedViews: z.array(z.any()),
    PlayDefaultAudioTrack: z.boolean(),
    RememberAudioSelections: z.boolean(),
    RememberSubtitleSelections: z.boolean(),
    SubtitleLanguagePreference: z.string(),
    SubtitleMode: z.string(),
});

const policy = z.object({
    AccessSchedules: z.array(z.any()),
    AuthenticationProviderId: z.string(),
    BlockedChannels: z.array(z.any()),
    BlockedMediaFolders: z.array(z.any()),
    BlockedTags: z.array(z.any()),
    BlockUnratedItems: z.array(z.any()),
    EnableAllChannels: z.boolean(),
    EnableAllDevices: z.boolean(),
    EnableAllFolders: z.boolean(),
    EnableAudioPlaybackTranscoding: z.boolean(),
    EnableContentDeletion: z.boolean(),
    EnableContentDeletionFromFolders: z.array(z.any()),
    EnableContentDownloading: z.boolean(),
    EnabledChannels: z.array(z.any()),
    EnabledDevices: z.array(z.any()),
    EnabledFolders: z.array(z.any()),
    EnableLiveTvAccess: z.boolean(),
    EnableLiveTvManagement: z.boolean(),
    EnableMediaConversion: z.boolean(),
    EnableMediaPlayback: z.boolean(),
    EnablePlaybackRemuxing: z.boolean(),
    EnablePublicSharing: z.boolean(),
    EnableRemoteAccess: z.boolean(),
    EnableRemoteControlOfOtherUsers: z.boolean(),
    EnableSharedDeviceControl: z.boolean(),
    EnableSyncTranscoding: z.boolean(),
    EnableUserPreferenceAccess: z.boolean(),
    EnableVideoPlaybackTranscoding: z.boolean(),
    ForceRemoteSourceTranscoding: z.boolean(),
    InvalidLoginAttemptCount: z.number(),
    IsAdministrator: z.boolean(),
    IsDisabled: z.boolean(),
    IsHidden: z.boolean(),
    LoginAttemptsBeforeLockout: z.number(),
    MaxActiveSessions: z.number(),
    PasswordResetProviderId: z.string(),
    RemoteClientBitrateLimit: z.number(),
    SyncPlayAccess: z.string(),
});

const user = z.object({
    Configuration: configuration,
    EnableAutoLogin: z.boolean(),
    HasConfiguredEasyPassword: z.boolean(),
    HasConfiguredPassword: z.boolean(),
    HasPassword: z.boolean(),
    Id: z.string(),
    LastActivityDate: z.string(),
    LastLoginDate: z.string(),
    Name: z.string(),
    Policy: policy,
    ServerId: z.string(),
});

const authenticateParameters = z.object({
    Pw: z.string(),
    Username: z.string(),
});

const authenticate = z.object({
    AccessToken: z.string(),
    ServerId: z.string(),
    SessionInfo: sessionInfo,
    User: user,
});

const genreItem = z.object({
    Id: z.string(),
    Name: z.string(),
});

const genre = z.object({
    BackdropImageTags: z.array(z.any()),
    ChannelId: z.null(),
    Id: z.string(),
    ImageBlurHashes: imageBlurHashes,
    ImageTags: imageTags,
    LocationType: z.string(),
    Name: z.string(),
    ServerId: z.string(),
    Type: z.string(),
});

const genreList = pagination.extend({
    Items: z.array(genre),
});

const genreListSort = {
    NAME: 'SortName',
} as const;

const genreListParameters = paginationParameters.merge(
    baseParameters.extend({
        SearchTerm: z.string().optional(),
        SortBy: z.nativeEnum(genreListSort).optional(),
    }),
);

const musicFolder = z.object({
    BackdropImageTags: z.array(z.string()),
    ChannelId: z.null(),
    CollectionType: z.string(),
    Id: z.string(),
    ImageBlurHashes: imageBlurHashes,
    ImageTags: imageTags,
    IsFolder: z.boolean(),
    LocationType: z.string(),
    Name: z.string(),
    ServerId: z.string(),
    Type: z.string(),
    UserData: userData,
});

const musicFolderListParameters = z.object({
    UserId: z.string(),
});

const musicFolderList = z.object({
    Items: z.array(musicFolder),
});

const playlist = z.object({
    BackdropImageTags: z.array(z.string()),
    ChannelId: z.null(),
    ChildCount: z.number().optional(),
    DateCreated: z.string(),
    GenreItems: z.array(genreItem),
    Genres: z.array(z.string()),
    Id: z.string(),
    ImageBlurHashes: imageBlurHashes,
    ImageTags: imageTags,
    IsFolder: z.boolean(),
    LocationType: z.string(),
    MediaType: z.string(),
    Name: z.string(),
    Overview: z.string().optional(),
    RunTimeTicks: z.number(),
    ServerId: z.string(),
    Type: z.string(),
    UserData: userData,
});

const playlistListSort = {
    ALBUM_ARTIST: 'AlbumArtist,SortName',
    DURATION: 'Runtime',
    NAME: 'SortName',
    RECENTLY_ADDED: 'DateCreated,SortName',
    SONG_COUNT: 'ChildCount',
} as const;

const playlistListParameters = paginationParameters.merge(
    baseParameters.extend({
        IncludeItemTypes: z.literal('Playlist'),
        SortBy: z.nativeEnum(playlistListSort).optional(),
    }),
);

const playlistList = pagination.extend({
    Items: z.array(playlist),
});

const genericItem = z.object({
    Id: z.string(),
    Name: z.string(),
});

const participant = z.object({
    Id: z.string(),
    Name: z.string(),
    Type: z.string().optional(),
});

const providerIds = z.object({
    MusicBrainzAlbum: z.string().optional(),
    MusicBrainzAlbumArtist: z.string().optional(),
    MusicBrainzArtist: z.string().optional(),
    MusicBrainzRecording: z.string().optional(),
    MusicBrainzReleaseGroup: z.string().optional(),
    MusicBrainzTrack: z.string().optional(),
});

const songDetailParameters = baseParameters;

const song = z.object({
    Album: z.string(),
    AlbumArtist: z.string(),
    AlbumArtists: z.array(genericItem),
    AlbumId: z.string().optional(),
    AlbumNormalizationGain: z.number().optional(),
    AlbumPrimaryImageTag: z.string(),
    ArtistItems: z.array(genericItem),
    Artists: z.array(z.string()),
    BackdropImageTags: z.array(z.string()),
    ChannelId: z.null(),
    DateCreated: z.string(),
    ExternalUrls: z.array(externalUrl),
    GenreItems: z.array(genericItem),
    Genres: z.array(z.string()),
    Id: z.string(),
    ImageBlurHashes: imageBlurHashes,
    ImageTags: imageTags,
    IndexNumber: z.number(),
    IsFolder: z.boolean(),
    LocationType: z.string(),
    LUFS: z.number().optional(),
    MediaSources: z.array(mediaSources),
    MediaType: z.string(),
    Name: z.string(),
    NormalizationGain: z.number().optional(),
    ParentId: z.string().optional(),
    ParentIndexNumber: z.number(),
    People: participant.array().optional(),
    PlaylistItemId: z.string().optional(),
    PremiereDate: z.string().optional(),
    ProductionYear: z.number(),
    ProviderIds: providerIds.optional(),
    RunTimeTicks: z.number(),
    ServerId: z.string(),
    SortName: z.string().optional(),
    Tags: z.string().array().optional(),
    Type: z.string(),
    UserData: userData.optional(),
});

const albumArtist = z.object({
    AlbumCount: z.number().optional(),
    BackdropImageTags: z.array(z.string()),
    ChannelId: z.null(),
    DateCreated: z.string(),
    ExternalUrls: z.array(externalUrl),
    GenreItems: z.array(genreItem),
    Genres: z.array(z.string()),
    Id: z.string(),
    ImageBlurHashes: imageBlurHashes,
    ImageTags: imageTags,
    LocationType: z.string(),
    Name: z.string(),
    Overview: z.string(),
    ProviderIds: providerIds.optional(),
    RunTimeTicks: z.number(),
    ServerId: z.string(),
    SongCount: z.number().optional(),
    Type: z.string(),
    UserData: userData.optional(),
});

const studio = z.object({
    Id: z.string(),
    Name: z.string(),
});

const albumDetailParameters = baseParameters;

const album = z.object({
    AlbumArtist: z.string(),
    AlbumArtists: z.array(genericItem),
    AlbumPrimaryImageTag: z.string(),
    ArtistItems: z.array(genericItem),
    Artists: z.array(z.string()),
    ChannelId: z.null(),
    ChildCount: z.number().optional(),
    DateCreated: z.string(),
    DateLastMediaAdded: z.string().optional(),
    ExternalUrls: z.array(externalUrl),
    GenreItems: z.array(genericItem),
    Genres: z.array(z.string()),
    Id: z.string(),
    ImageBlurHashes: imageBlurHashes,
    ImageTags: imageTags,
    IsFolder: z.boolean(),
    LocationType: z.string(),
    Name: z.string(),
    ParentLogoImageTag: z.string(),
    ParentLogoItemId: z.string(),
    People: participant.array().optional(),
    PremiereDate: z.string().optional(),
    ProductionYear: z.number(),
    ProviderIds: providerIds.optional(),
    RunTimeTicks: z.number(),
    ServerId: z.string(),
    Songs: z.array(song).optional(), // This is not a native Jellyfin property -- this is used for combined album detail
    SortName: z.string().optional(),
    Studios: z.array(studio),
    Tags: z.string().array().optional(),
    Type: z.string(),
    UserData: userData.optional(),
});

const albumListSort = {
    ALBUM_ARTIST: 'AlbumArtist,SortName',
    COMMUNITY_RATING: 'CommunityRating,SortName',
    CRITIC_RATING: 'CriticRating,SortName',
    NAME: 'SortName',
    PLAY_COUNT: 'PlayCount',
    RANDOM: 'Random,SortName',
    RECENTLY_ADDED: 'DateCreated,SortName',
    RELEASE_DATE: 'ProductionYear,PremiereDate,SortName',
} as const;

const albumListParameters = paginationParameters.merge(
    baseParameters.extend({
        Filters: z.string().optional(),
        GenreIds: z.string().optional(),
        Genres: z.string().optional(),
        IncludeItemTypes: z.literal('MusicAlbum'),
        IsFavorite: z.boolean().optional(),
        SearchTerm: z.string().optional(),
        SortBy: z.nativeEnum(albumListSort).optional(),
        Tags: z.string().optional(),
        Years: z.string().optional(),
    }),
);

const albumList = pagination.extend({
    Items: z.array(album),
});

const albumArtistListSort = {
    ALBUM: 'Album,SortName',
    DURATION: 'Runtime,AlbumArtist,Album,SortName',
    NAME: 'SortName,Name',
    RANDOM: 'Random,SortName',
    RECENTLY_ADDED: 'DateCreated,SortName',
    RELEASE_DATE: 'PremiereDate,AlbumArtist,Album,SortName',
} as const;

const albumArtistListParameters = paginationParameters.merge(
    baseParameters.extend({
        Filters: z.string().optional(),
        Genres: z.string().optional(),
        SortBy: z.nativeEnum(albumArtistListSort).optional(),
        Years: z.string().optional(),
    }),
);

const albumArtistList = pagination.extend({
    Items: z.array(albumArtist),
});

const similarArtistListParameters = baseParameters.extend({
    Limit: z.number().optional(),
});

const songListSort = {
    ALBUM: 'Album,SortName',
    ALBUM_ARTIST: 'AlbumArtist,Album,SortName',
    ALBUM_DETAIL: 'ParentIndexNumber,IndexNumber,SortName',
    ARTIST: 'Artist,Album,SortName',
    COMMUNITY_RATING: 'CommunityRating,SortName',
    DURATION: 'Runtime,AlbumArtist,Album,SortName',
    NAME: 'Name',
    PLAY_COUNT: 'PlayCount,SortName',
    RANDOM: 'Random,SortName',
    RECENTLY_ADDED: 'DateCreated,SortName',
    RECENTLY_PLAYED: 'DatePlayed,SortName',
    RELEASE_DATE: 'PremiereDate,AlbumArtist,Album,SortName',
} as const;

const songListParameters = paginationParameters.merge(
    baseParameters.extend({
        AlbumArtistIds: z.string().optional(),
        AlbumIds: z.string().optional(),
        ArtistIds: z.string().optional(),
        Filters: z.string().optional(),
        GenreIds: z.string().optional(),
        Genres: z.string().optional(),
        IsFavorite: z.boolean().optional(),
        IsPlayed: z.boolean().optional(),
        SearchTerm: z.string().optional(),
        SortBy: z.nativeEnum(songListSort).optional(),
        Tags: z.string().optional(),
        Years: z.string().optional(),
    }),
);

const songList = pagination.extend({
    Items: z.array(song),
});

const playlistSongList = songList;

const topSongsList = songList;

const playlistDetailParameters = baseParameters.extend({
    Ids: z.string(),
});

const createPlaylistParameters = z.object({
    IsPublic: z.boolean().optional(),
    MediaType: z.literal('Audio'),
    Name: z.string(),
    UserId: z.string(),
});

const createPlaylist = z.object({
    Id: z.string(),
});

const updatePlaylist = z.null();

const updatePlaylistParameters = z.object({
    Ids: z.string().array().optional(),
    IsPublic: z.boolean().optional(),
    Name: z.string().optional(),
});

const addToPlaylist = z.object({
    Added: z.number(),
});

const addToPlaylistParameters = z.object({
    Ids: z.string(),
    UserId: z.string(),
});

const removeFromPlaylist = z.null();

const removeFromPlaylistParameters = z.object({
    EntryIds: z.string(),
});

const deletePlaylist = z.null();

const deletePlaylistImage = z.null();

const deleteArtistImage = deletePlaylistImage;

const uploadPlaylistImage = z.null();

const uploadArtistImage = uploadPlaylistImage;

const deletePlaylistParameters = z.object({
    Id: z.string(),
});

const scrobbleParameters = z.object({
    EventName: z.string().optional(),
    IsPaused: z.boolean().optional(),
    ItemId: z.string(),
    PositionTicks: z.number().optional(),
});

const scrobble = z.any();

const favorite = z.object({
    IsFavorite: z.boolean(),
    ItemId: z.string(),
    Key: z.string(),
    LastPlayedDate: z.string(),
    Likes: z.boolean(),
    PlaybackPositionTicks: z.number(),
    PlayCount: z.number(),
    Played: z.boolean(),
    PlayedPercentage: z.number(),
    Rating: z.number(),
    UnplayedItemCount: z.number(),
});

const favoriteParameters = z.object({});

const searchParameters = paginationParameters.merge(baseParameters);

const search = z.any();

const lyricText = z.object({
    Start: z.number().optional(),
    Text: z.string(),
});

const lyrics = z.object({
    Lyrics: z.array(lyricText),
});

const serverInfo = z.object({
    Version: z.string(),
});

const taskTriggerInfo = z.object({
    DayOfWeek: z.string().nullish(),
    IntervalTicks: z.number().nullish(),
    MaxRuntimeTicks: z.number().nullish(),
    TimeOfDayTicks: z.number().nullish(),
    Type: z.string().nullish(),
});

const taskResult = z.object({
    EndTimeUtc: z.string().nullish(),
    ErrorMessage: z.string().nullish(),
    Id: z.string().nullish(),
    Key: z.string().nullish(),
    LongErrorMessage: z.string().nullish(),
    Name: z.string().nullish(),
    StartTimeUtc: z.string().nullish(),
    Status: z.string().nullish(),
});

const taskInfo = z.object({
    Category: z.string().nullish(),
    CurrentProgressPercentage: z.number().nullish(),
    Description: z.string().nullish(),
    Id: z.string().nullish(),
    IsHidden: z.boolean().optional(),
    Key: z.string().nullish(),
    LastExecutionResult: taskResult.nullish(),
    Name: z.string().nullish(),
    State: z.enum(['Idle', 'Cancelling', 'Running']).optional(),
    Triggers: z.array(taskTriggerInfo).nullish(),
});

const scheduledTasks = z.array(taskInfo);

const similarSongsParameters = z.object({
    Fields: z.array(z.string()).readonly().optional(),
    Limit: z.number().optional(),
    UserId: z.string().optional(),
});

const similarSongs = pagination.extend({
    Items: z.array(song),
});

export enum JellyfinExtensions {
    SONG_LYRICS = 'songLyrics',
}

const moveItem = z.null();

const filterListParameters = z.object({
    IncludeItemTypes: z.string().optional(),
    ParentId: z.string().optional(),
    UserId: z.string().optional(),
});

const filters = z.object({
    Genres: z.string().array().optional(),
    Tags: z.string().array().optional(),
    Years: z.number().array().optional(),
});

const folder = z.object({
    BackdropImageTags: z.array(z.string()),
    ChannelId: z.null(),
    CollectionType: z.string(),
    Id: z.string(),
    ImageBlurHashes: imageBlurHashes,
    ImageTags: imageTags,
    IsFolder: z.boolean(),
    LocationType: z.string(),
    MediaType: z.string(),
    Name: z.string(),
    ParentId: z.string().optional(),
    ServerId: z.string(),
    Type: z.string(),
    UserData: userData.optional(),
});

const folderList = pagination.extend({
    Items: z.array(folder),
});

const folderParameters = z.object({
    Fields: z.array(z.string()).readonly().optional(),
    ParentId: z.string().optional(),
    SortBy: z.string().optional(),
    SortOrder: z.enum(sortOrderValues).optional(),
});

const queueItem = z.object({
    Id: z.string(),
    PlaylistItemId: z.string().optional(),
});

const saveQueueParameters = scrobbleParameters.merge(
    z.object({
        NowPlayingQueue: z.array(queueItem),
        PlaylistItemId: z.string().optional(),
    }),
);

const getQueueParameters = z.object({});

const getSessions = z.array(
    sessionInfo.merge(
        z.object({
            PlaylistItemId: z.string().optional(),
        }),
    ),
);

const studioListParameters = paginationParameters.merge(
    baseParameters.extend({
        NameStartsWithOrGreater: z.string().optional(),
    }),
);

const studioList = z.object({
    Items: z.array(studio),
});

export const jfType = {
    _enum: {
        albumArtistList: albumArtistListSort,
        albumList: albumListSort,
        collection: jfCollection,
        external: jfExternal,
        genreList: genreListSort,
        image: jfImage,
        playlistList: playlistListSort,
        songList: songListSort,
    },
    _parameters: {
        addToPlaylist: addToPlaylistParameters,
        albumArtistDetail: baseParameters,
        albumArtistList: albumArtistListParameters,
        albumDetail: albumDetailParameters,
        albumList: albumListParameters,
        authenticate: authenticateParameters,
        createPlaylist: createPlaylistParameters,
        deletePlaylist: deletePlaylistParameters,
        favorite: favoriteParameters,
        filterList: filterListParameters,
        folder: folderParameters,
        genreList: genreListParameters,
        getQueue: getQueueParameters,
        musicFolderList: musicFolderListParameters,
        playlistDetail: playlistDetailParameters,
        playlistList: playlistListParameters,
        removeFromPlaylist: removeFromPlaylistParameters,
        saveQueue: saveQueueParameters,
        scrobble: scrobbleParameters,
        search: searchParameters,
        similarArtistList: similarArtistListParameters,
        similarSongs: similarSongsParameters,
        songDetail: songDetailParameters,
        songList: songListParameters,
        studioList: studioListParameters,
        updatePlaylist: updatePlaylistParameters,
    },
    _response: {
        addToPlaylist,
        album,
        albumArtist,
        albumArtistList,
        albumList,
        authenticate,
        createPlaylist,
        deleteArtistImage,
        deletePlaylist,
        deletePlaylistImage,
        error,
        favorite,
        filters,
        folder,
        folderList,
        genre,
        genreList,
        getSessions,
        lyrics,
        moveItem,
        musicFolder,
        musicFolderList,
        playlist,
        playlistList,
        playlistSongList,
        removeFromPlaylist,
        scheduledTasks,
        scrobble,
        search,
        serverInfo,
        similarSongs,
        song,
        songList,
        studioList,
        topSongsList,
        updatePlaylist,
        uploadArtistImage,
        uploadPlaylistImage,
        user,
    },
};
