use lofty::{prelude::*, probe::Probe};
use log::error;
use std::path::PathBuf;

pub struct TrackMetadata {
    path: PathBuf,
    artist: Option<String>,
    album: Option<String>,
    title: String,
    duration: String,
}

impl Default for TrackMetadata {
    fn default() -> Self {
        TrackMetadata {
            path: PathBuf::new(),
            artist: None,
            album: None,
            title: String::new(),
            duration: String::new(),
        }
    }
}

impl TrackMetadata {
    pub fn artist(&self) -> Option<&str> {
        self.artist.as_deref()
    }

    pub fn title(&self) -> &str {
        self.title.as_ref()
    }

    pub fn album(&self) -> Option<&str> {
        self.album.as_deref()
    }

    pub fn path(&self) -> &PathBuf {
        &self.path
    }

    pub fn duration(&self) -> &str {
        self.duration.as_ref()
    }

    pub fn new(path: &PathBuf) -> Self {
        let file_probe = match Probe::open(path) {
            Ok(p) => p,
            Err(e) => {
                error!("Error to open file {:?}: {}", path, e);
                return Self::default();
            }
        };

        let tagged_file = match file_probe.guess_file_type() {
            Ok(t) => match t.read() {
                Ok(f) => f,
                Err(e) => {
                    error!("Error to read parsed file {:?}: {}", path, e);
                    return Self::default();
                }
            },
            Err(e) => {
                error!("Error to parse file type {:?}: {}", path, e);
                return Self::default();
            }
        };

        let mut artist = None;
        let mut title = None;
        let mut album = None;

        if let Some(tag) = tagged_file.primary_tag() {
            artist = tag.artist().map(|s| s.to_string());
            title = tag.title().map(|s| s.to_string());
            album = tag.album().map(|s| s.to_string());
        } else {
            for tag in tagged_file.tags() {
                artist = tag.artist().map(|s| s.to_string());
                title = tag.title().map(|s| s.to_string());
                album = tag.album().map(|s| s.to_string());
            }
        }
        let return_title = title.unwrap_or_else(|| {
            path.file_stem()
                .and_then(|s| s.to_str())
                .unwrap_or("Unknown")
                .to_string()
        });

        let properties = lofty::prelude::AudioFile::properties(&tagged_file);
        let duration = properties.duration().as_secs().to_string();

        TrackMetadata {
            path: path.to_path_buf(),
            title: return_title,
            artist,
            album,
            duration,
        }
    }
}
