use crate::prelude::*;
use ExistingFormat::*;
use clap::ValueEnum;
use std::cmp::Ordering;

/// Format of an existing release.
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize, ValueEnum)]
#[serde(rename_all = "lowercase")]
pub enum ExistingFormat {
    Flac24 = 0,
    Flac = 1,
    #[serde(rename = "320")]
    _320 = 2,
    V0 = 3,
}

impl ExistingFormat {
    /// Determine format from torrent metadata.
    pub fn from_torrent(torrent: &Torrent) -> Option<ExistingFormat> {
        match (&torrent.format, &torrent.encoding) {
            (Format::FLAC, Quality::Lossless) => Some(Flac),
            (Format::FLAC, Quality::Lossless24) => Some(Flac24),
            (Format::MP3, Quality::_320) => Some(_320),
            (Format::MP3, Quality::V0) => Some(V0),
            (format, encoding) => {
                trace!(
                    "{} to determine ExistingFormat of `{format}` with encoding `{encoding}`",
                    "Failed".bold()
                );
                None
            }
        }
    }

    /// Display name of the format.
    #[must_use]
    pub fn get_name(&self) -> &str {
        match self {
            Flac24 => "FLAC 24bit",
            Flac => "FLAC",
            _320 => "320",
            V0 => "V0",
        }
    }

    /// Convert to [`SourceFormat`] if this is a lossless format.
    pub fn to_source(self) -> Option<SourceFormat> {
        match self {
            Flac24 => Some(SourceFormat::Flac24),
            Flac => Some(SourceFormat::Flac),
            _ => None,
        }
    }
}

impl Display for ExistingFormat {
    fn fmt(&self, formatter: &mut Formatter<'_>) -> FmtResult {
        write!(formatter, "{}", self.get_name())
    }
}

impl PartialOrd for ExistingFormat {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for ExistingFormat {
    #[allow(clippy::as_conversions)]
    fn cmp(&self, other: &Self) -> Ordering {
        let left = *self as isize;
        let right = *other as isize;
        left.cmp(&right)
    }
}
