use std::path::PathBuf;

use crate::media::entity::{MediaFile, MediaFileInput, VideoStreamResponse};

pub trait TreeWalker {
    fn next(&mut self) -> impl Future<Output = anyhow::Result<Option<MediaFileInput>>> + Send;
}

#[cfg_attr(any(test, feature = "mocks"), auto_impl::auto_impl(Arc))]
#[cfg_attr(any(test, feature = "mocks"), mockall::automock)]
pub trait MediaService: Send + Sync + 'static {
    fn video_stream(
        &self,
        media_id: u64,
    ) -> impl Future<Output = anyhow::Result<Option<VideoStreamResponse>>> + Send;
    fn synchronize(&self, disk: &str) -> impl Future<Output = anyhow::Result<()>> + Send;
    fn request_synchronize_all(
        &self,
        user_id: Option<u64>,
    ) -> impl Future<Output = anyhow::Result<()>> + Send;
    fn synchronize_all(&self) -> impl Future<Output = anyhow::Result<()>> + Send;
}

pub trait MediaStore: Send + Sync + 'static {
    type Walker: Send + TreeWalker;

    fn disks(&self) -> Vec<String>;
    fn traverse(&self, disk: &str, path: &str) -> anyhow::Result<Option<Self::Walker>>;
    fn video_stream(
        &self,
        disk: &str,
        path: PathBuf,
    ) -> impl Future<Output = anyhow::Result<Option<VideoStreamResponse>>> + Send;
}

pub trait MediaRepository: Send + Sync + 'static {
    fn find_by_id(
        &self,
        media_id: u64,
    ) -> impl Future<Output = anyhow::Result<Option<MediaFile>>> + Send;
    fn upsert(
        &self,
        disk: &str,
        input: &[MediaFileInput],
    ) -> impl Future<Output = anyhow::Result<u64>> + Send;
}
