use std::path::PathBuf;
use std::io::BufReader;
use std::thread;
use std::time::Duration;
use std::fs::File;
use std::io::{Cursor, Read, Seek, SeekFrom, Write};
use std::sync::Arc;
use rodio::Decoder;
use crate::rodio::Source;


// pub fn collect


pub struct Snd (Arc<Vec<u8>>);

impl AsRef<[u8]> for Snd {
    fn as_ref(&self) -> &[u8] {
        &self.0
    }
}

impl Snd {
    pub fn load(filename: &str) -> std::io::Result<Snd> {
        let mut buf = Vec::new();
        let mut file = File::open(filename)?;
        file.read_to_end(&mut buf)?;
        Ok(Snd(Arc::new(buf)))
    }
    pub fn cursor(self: &Self) -> Cursor<Snd> {
        Cursor::new(Snd(self.0.clone()))
    }
    pub fn decoder(self: &Self) -> Decoder<Cursor<Snd>> {
        Decoder::new(self.cursor()).unwrap()
    }
}

#[derive(Clone, Default, Debug)]
pub struct Sound {
    pub location: PathBuf,
    data: Arc<Vec<u8>>,
    volume: f32,
    pub roll: i32,
    pub rate: i32
}


impl AsRef<[u8]> for Sound {
    fn as_ref(&self) -> &[u8] {
        &self.data
    }
}

impl Sound {

    pub fn new(filename: &str) -> std::io::Result<Sound> {
        let mut buf = Vec::new();
        let mut file = File::open(filename)?;
        file.read_to_end(&mut buf)?;
        Ok(Sound{
            data: Arc::new(buf),
            ..Default::default()
        })
    }
    pub fn cursor(self: &Self) -> Cursor<Sound> {
        Cursor::new(
            Sound {
                data: self.data.clone(),
                ..Default::default()
            })
    }

    pub fn decoder(self: &Self) -> Decoder<Cursor<Sound>> {
        Decoder::new(self.cursor()).unwrap()
    }


    pub fn play(&self, device: &rodio::Device) {
        rodio::play_raw(&device, self.decoder().convert_samples());
    }
}

pub struct Bar {
    pub repeat: i32,
    pub length: i32,
    pub bpm: i32,
    pub sounds: Vec<Sound>
}

impl Default for Bar {
    fn default() -> Bar {
        Bar {
            repeat: 0,
            length: 4,
            bpm: 120,
            sounds: vec![]
        }
    }
}

impl Bar {
    pub fn play(&self, device: &rodio::Device) {
        let delay = ((60.0 / self.bpm as f32)*1000.0) as u64;
        for _ in 0..self.repeat+1 {
            for sound in &self.sounds {
                sound.play(device);
                thread::sleep(Duration::from_millis(delay));
            }
        }
    }
}