// Copyright 2022 the Vello Authors
// SPDX-License-Identifier: Apache-2.0 OR MIT

//! Scenes

// The following lints are part of the Linebender standard set,
// but resolving them has been deferred for now.
// Feel free to send a PR that solves one or more of these.
#![allow(
    missing_debug_implementations,
    unreachable_pub,
    missing_docs,
    clippy::cast_possible_truncation,
    clippy::allow_attributes_without_reason
)]

mod images;
mod mmark;
mod pico_svg;
mod simple_text;
mod svg;
pub mod test_scenes;

use clap::Args;
pub use images::ImageCache;
pub use simple_text::SimpleText;
use std::path::PathBuf;
pub use svg::{default_scene, scene_from_files};
use test_scenes::test_scenes;

use vello::Scene;
use vello::kurbo::Vec2;
use vello::peniko::{Color, color};

pub struct SceneParams<'a> {
    pub time: f64,
    /// Whether blocking should be limited
    /// Will not change between runs
    // TODO: Just never block/handle this automatically?
    pub interactive: bool,
    pub text: &'a mut SimpleText,
    pub images: &'a mut ImageCache,
    pub resolution: Option<Vec2>,
    pub base_color: Option<Color>,
    pub complexity: usize,
}

pub struct SceneConfig {
    // TODO: This is currently unused
    pub animated: bool,
    pub name: String,
}

pub struct ExampleScene {
    pub function: Box<dyn TestScene>,
    pub config: SceneConfig,
}

pub trait TestScene {
    fn render(&mut self, scene: &mut Scene, params: &mut SceneParams<'_>);
}

impl<F: FnMut(&mut Scene, &mut SceneParams<'_>)> TestScene for F {
    fn render(&mut self, scene: &mut Scene, params: &mut SceneParams<'_>) {
        self(scene, params);
    }
}

pub struct SceneSet {
    pub scenes: Vec<ExampleScene>,
}

#[derive(Args, Debug)]
/// Shared config for scene selection
pub struct Arguments {
    #[arg(help_heading = "Scene Selection")]
    #[arg(long, global(false))]
    /// Whether to use the test scenes created by code
    test_scenes: bool,
    #[arg(help_heading = "Scene Selection", global(false))]
    /// The svg files paths to render
    svgs: Option<Vec<PathBuf>>,
    #[arg(help_heading = "Render Parameters")]
    #[arg(long, global(false), value_parser = parse_color_arg)]
    /// The base color applied as the blend background to the rasterizer.
    /// Format is CSS style hexadecimal (#RGB, #RGBA, #RRGGBB, #RRGGBBAA) or
    /// an SVG color name such as "aliceblue"
    pub base_color: Option<Color>,
}

impl Arguments {
    pub fn select_scene_set(&self) -> anyhow::Result<Option<SceneSet>> {
        // There is no file access on WASM, and on Android we haven't set up the assets
        // directory.
        // TODO: Upload the assets directory on Android
        // Therefore, only render the `test_scenes` (including one SVG example)
        #[cfg(any(target_arch = "wasm32", target_os = "android"))]
        return Ok(Some(test_scenes()));
        #[cfg(not(any(target_arch = "wasm32", target_os = "android")))]
        if self.test_scenes {
            Ok(test_scenes())
        } else if let Some(svgs) = &self.svgs {
            scene_from_files(svgs)
        } else {
            default_scene()
        }
        .map(Some)
    }
}

fn parse_color_arg(s: &str) -> Result<Color, color::ParseError> {
    color::parse_color(s).map(|c| c.to_alpha_color())
}
