use std::path::Path;

use anyhow::Ok;
use av_decoders::Ffms2Decoder;
#[cfg(feature = "vapoursynth")]
use vapoursynth::video_info::VideoInfo;

pub fn get_ffms2_instance(input_path: &str) -> Ffms2Decoder {
    av_decoders::Ffms2Decoder::new(input_path).unwrap()
}

pub fn set_ffms2_format(
    videosource: &mut Ffms2Decoder,
    height: Option<usize>,
    width: Option<usize>,
    bitdepth: u8,
) -> anyhow::Result<&mut Ffms2Decoder> {
    let chroma_subsampling = videosource.video_details.chroma_sampling;

    let real_width = width.unwrap_or(videosource.video_details.width);
    let real_height = height.unwrap_or(videosource.video_details.height);

    if let Err(e) =
        videosource.set_output_format(real_width, real_height, bitdepth, chroma_subsampling)
    {
        eprintln!("Warning: failed to set FFMS2 output format: {e}");
    }

    Ok(videosource)
}

pub fn ffms2_get_scene_len(
    videosource: &mut Ffms2Decoder,
    min_scene_len: Option<&isize>,
    max_scene_len: Option<&isize>,
) -> (Option<usize>, Option<usize>) {
    let default_min_len = videosource.video_details.frame_rate.round().to_integer() as usize;
    let default_max_len = {
        let fps = videosource.video_details.frame_rate.round().to_integer() as usize;

        (fps * 10).min(300)
    };

    let min_len = min_scene_len.and_then(|x| {
        if *x == -1 {
            Some(default_min_len)
        } else {
            usize::try_from(*x).ok()
        }
    });

    let max_len = max_scene_len.and_then(|x| {
        if *x == -1 {
            Some(default_max_len)
        } else {
            usize::try_from(*x).ok()
        }
    });

    (min_len, max_len)
}

#[cfg(feature = "vapoursynth")]
pub fn vs_get_scene_len(
    info: &VideoInfo,
    min_scene_len: Option<&isize>,
    max_scene_len: Option<&isize>,
) -> anyhow::Result<(Option<usize>, Option<usize>)> {
    use anyhow::bail;
    use vapoursynth::prelude::Property;
    match info.framerate {
        Property::Variable => bail!("Cannot use clips with varying framerate"),
        Property::Constant(fps) => {
            let fps_numerator = fps.numerator as f64;
            let fps_denominator = fps.denominator as f64;

            let final_fps = fps_numerator / fps_denominator;

            let default_min_len = final_fps.round() as usize;
            let default_max_len = (final_fps * 10.0).round() as usize;

            let min_len = min_scene_len.and_then(|x| {
                if *x == -1 {
                    Some(default_min_len)
                } else {
                    usize::try_from(*x).ok()
                }
            });

            let max_len = max_scene_len.and_then(|x| {
                if *x == -1 {
                    Some(default_max_len)
                } else {
                    usize::try_from(*x).ok()
                }
            });

            if min_len > max_len {
                bail!("min_scene_len cannot be greater than max_scene_len");
            }

            Ok((min_len, max_len))
        },
    }
}

pub fn is_vapoursynth_script(input: &Path) -> bool {
    matches!(
        input.extension().and_then(|ext| ext.to_str()),
        Some(ext) if ext.eq_ignore_ascii_case("vpy") || ext.eq_ignore_ascii_case("py")
    )
}
