use super::{
    Database, DatabaseError,
    entities::{ContinueWatchingMovie, FileRow, ImageRow, Movie, MovieWithCover, NewMovie},
    queries,
};
use rusqlite::params;

impl Database {
    db_query_all!(fn find_matched_movies() -> Vec<Movie>, queries::find_matched_movies);
    db_query_all!(fn find_movies_with_covers() -> Vec<MovieWithCover>, queries::find_movies_with_covers);
    db_query_all!(fn find_unmatched_movies() -> Vec<Movie>, queries::find_unmatched_movies);
    db_query_all!(fn find_recent_movies_with_covers() -> Vec<MovieWithCover>, queries::find_recent_movies_with_covers);
    db_query_all!(fn find_all_images() -> Vec<ImageRow>, queries::find_all_images); // TODO: this query belongs not to movies
    db_query_all!(fn find_continue_watching_movies() -> Vec<ContinueWatchingMovie>, queries::find_continue_watching_movies);

    db_exec!(fn set_movie_watched(watched: bool, id: i64), queries::set_movie_watched);
    db_exec!(fn update_movie_playback(position: f64, id: i64), queries::update_movie_playback);
    db_exec!(fn clear_movie_playback(id: i64), queries::clear_movie_playback);
    db_exec!(fn set_movie_skip_auto_match(id: i64), queries::set_movie_skip_auto_match);
    db_exec!(fn reset_movie_auto_match(), queries::reset_movie_auto_match);
    db_exec!(fn delete_orphaned_images(), queries::delete_orphaned_images); // TODO: this query belongs not to movies
    db_exec!(fn delete_movie_images(movie_id: i64, image_type: &str), queries::delete_movie_images);
    db_exec!(fn link_movie_image(movie_id: i64, image_id: i64, image_type: &str), queries::link_movie_image);

    pub fn create_movie(&mut self, new_movie: NewMovie) -> Result<i64, DatabaseError> {
        let (_, id) = self.exec_cmd(
            &queries::create_movie,
            params![
                new_movie.library_id,
                Option::<i64>::None,
                new_movie.title,
                Option::<String>::None,
                new_movie.release_year,
                new_movie.file
            ],
        )?;

        Ok(id)
    }

    pub fn update_movie_tmdb(
        &mut self,
        movie_id: i64,
        tmdb_id: i64,
        original_title: &str,
        description: Option<&str>,
        rating: Option<f64>,
    ) -> Result<(), DatabaseError> {
        self.exec_cmd(
            &queries::update_movie_tmdb,
            params![tmdb_id, original_title, description, rating, movie_id],
        )?;
        Ok(())
    }

    pub fn create_image(
        &mut self,
        image: &[u8],
        filename: &str,
        mime_type: &str,
    ) -> Result<i64, DatabaseError> {
        let (_, id) = self.exec_cmd(
            &queries::create_image,
            params![image, filename, mime_type, image.len() as i64],
        )?;
        Ok(id)
    }

    pub fn find_movie_files_by_library(
        &mut self,
        library_id: i64,
    ) -> Result<Vec<String>, DatabaseError> {
        let rows: Vec<FileRow> =
            self.query_all(&queries::find_movie_files_by_library, [library_id])?;
        Ok(rows.into_iter().map(|r| r.file).collect())
    }
}
