from dataclasses import dataclass
from enum import StrEnum
from pathlib import Path

from ..tools.schema.define import schema
from ..tools.schema.fields import Url
from .artwork import Artwork
from .musicbrainz import MusicBrainzIds


class PlaybackState(StrEnum):
	play = "play"
	pause = "pause"
	stop = "stop"


@schema("https://cdn.00dani.me/m/schemata/mpd-now-playable/song-v1.json")
@dataclass(slots=True, kw_only=True)
class Song:
	#: Whether MPD is currently playing, paused, or stopped. Pretty simple.
	state: PlaybackState

	#: The zero-based index of the current song in MPD's queue.
	queue_index: int
	#: The total length of MPD's queue - the last song in the queue will have
	#: the index one less than this, since queue indices are zero-based.
	queue_length: int

	#: The relative path to the current song inside the music directory. MPD
	#: itself uses this path as a stable identifier for the audio file in many
	#: places, so you can safely do the same.
	file: Path

	#: An absolute URL referring to the current song, if available. If the
	#: song's a local file and its absolute path can be determined
	#: (mpd-now-playable has been configured with your music directory), then
	#: this field will contain a file:// URL. If the song's remote, then MPD
	#: itself returns an absolute URL in the first place.
	url: Url | None = None

	#: The song's title, if it's been tagged with one. Currently only one title
	#: is supported, since it doesn't make a lot of sense to tag a single audio
	#: file with multiple titles.
	title: str | None

	#: The song's artists. Will be an empty list if the song has not been
	#: tagged with an artist, and may contain multiple values if the song has
	#: been tagged with several artists.
	artist: list[str]
	#: The song's composers. Again, this is permitted to be multivalued.
	composer: list[str]
	#: The name of the song's containing album, which may be multivalued.
	album: list[str]
	#: The album's artists. This is often used to group together songs from a
	#: single album that featured different artists.
	album_artist: list[str]

	#: The track number the song has on its album. This is usually one-based,
	#: but it's just an arbitrary audio tag so a particular album might start
	#: at zero or do something weird with it.
	track: int | None

	#: The disc number of the song on its album. As with the track number, this
	#: is usually one-based, but it doesn't have to be.
	disc: int | None

	#: The song's genre or genres. These are completely arbitrary descriptions
	#: and don't follow any particular standard.
	genre: list[str]

	#: The song's duration as read from its tags, measured in seconds.
	#: Fractional seconds are allowed.
	duration: float

	#: How far into the song MPD is, measured in seconds. Fractional seconds
	#: are allowed. This is usually going to be less than or equal to the
	#: song's duration, but because the duration is tagged as metadata and this
	#: value represents the actual elapsed time, it might go higher if the
	#: song's duration tag is inaccurate.
	elapsed: float

	#: The song's cover art, if it has any - the art will be available as bytes
	#: if present, ready to be displayed directly by receivers.
	art: Artwork

	#: The MusicBrainz IDs associated with the song and with its artist and
	#: album, which if present are an extremely accurate way to identify a
	#: given song. They're not always present, though.
	musicbrainz: MusicBrainzIds