use std::{
    fs,
    io::{Read, Seek},
    path::Path,
};

use symphonia::core::{
    formats::{FormatOptions, TrackType, probe::Hint},
    io::MediaSourceStream,
    meta::{MetadataOptions, MetadataRevision},
};

use crate::media_container::{ContainerError, ContainerFormat, MediaContainer, Stream};

pub mod raw_decoder;

pub struct ContainerExtractResult {
    pub container: MediaContainer,
    pub metadata: Option<MetadataRevision>,
}

pub fn extract_from_file(path: impl AsRef<Path>) -> Result<ContainerExtractResult, ContainerError> {
    let path = path.as_ref();
    let mut file = fs::File::open(path)?;

    let mut buf = [0_u8; 16];
    file.read_exact(&mut buf)?;
    file.seek(std::io::SeekFrom::Start(0))?;

    let container_format = ContainerFormat::from_buf(&buf)
        .ok_or_else(|| ContainerError::InvalidSource(path.to_path_buf()))?;

    let mss = MediaSourceStream::new(Box::new(file), Default::default());
    let fmt_opts = FormatOptions::default();
    let metadata_opts = MetadataOptions::default();
    let mut probe =
        symphonia::default::get_probe().probe(&Hint::new(), mss, fmt_opts, metadata_opts)?;

    let track = probe.default_track(TrackType::Audio).unwrap();
    let stream = Stream::try_from(track)?;

    let container = MediaContainer {
        path: path.to_path_buf(),
        format: container_format,
        stream,
    };

    Ok(ContainerExtractResult {
        container,
        metadata: probe.metadata().pop(),
    })
}
