Preview App
use std::f64::consts::PI;

use glam::{DVec3, dvec2, dvec3};
use itertools::Itertools;
use log::LevelFilter;
use ranim::{
    animation::{creation::WritingAnim, lagged::LaggedAnim, transform::TransformAnim},
    color::palettes::manim,
    components::{Anchor, ScaleHint},
    items::{
        Group,
        vitem::{
            VItem,
            geometry::{Polygon, Rectangle, Square},
            svg::SvgItem,
            typst::typst_svg,
        },
    },
    prelude::*,
    timeline::TimeMark,
    utils::rate_functions::{linear, smooth},
};

fn build_logo(logo_width: f64) -> [VItem; 6] {
    let red_bg_rect = Rectangle::new(logo_width / 2.0, logo_width).with(|rect| {
        rect.set_color(manim::RED_C.with_alpha(0.5))
            .put_center_on(dvec3(-logo_width / 4.0, 0.0, 0.0));
    });
    let red_rect = Rectangle::new(logo_width / 4.0, logo_width).with(|rect| {
        rect.set_color(manim::RED_C)
            .put_anchor_on(Anchor::edge(1, 0, 0), dvec3(-logo_width / 4.0, 0.0, 0.0));
    });

    let green_bg_sq = Square::new(logo_width / 2.0).with(|sq| {
        sq.set_color(manim::GREEN_C.with_alpha(0.5))
            .put_center_on(dvec3(logo_width / 4.0, logo_width / 4.0, 0.0));
    });
    let green_triangle = Polygon::new(vec![
        dvec3(0.0, logo_width / 2.0, 0.0),
        dvec3(logo_width / 2.0, logo_width / 2.0, 0.0),
        dvec3(logo_width / 2.0, 0.0, 0.0),
    ])
    .with(|tri| {
        tri.set_color(manim::GREEN_C);
    }); //
    let blue_bg_sq = Square::new(logo_width / 2.0).with(|sq| {
        sq.set_color(manim::BLUE_C.with_alpha(0.5))
            .put_center_on(dvec3(logo_width / 4.0, -logo_width / 4.0, 0.0));
    });
    let blue_triangle = green_triangle.clone().with(|tri| {
        tri.set_color(manim::BLUE_C)
            .rotate(PI, DVec3::Z)
            .shift(DVec3::NEG_Y * logo_width / 2.0);
    }); //
    [
        VItem::from(red_bg_rect),
        VItem::from(red_rect),
        VItem::from(green_bg_sq),
        VItem::from(green_triangle),
        VItem::from(blue_bg_sq),
        VItem::from(blue_triangle),
    ]
}
#[scene]
#[preview]
#[output(dir = "ranim_logo")]
fn ranim_logo(r: &mut RanimScene) {
    let _r_cam = r.insert_and_show(CameraFrame::default());
    let frame_size = dvec2(8.0 * 16.0 / 9.0, 8.0);
    let logo_width = frame_size.y * 0.618;

    let logo = build_logo(logo_width);
    let r_logo = logo.map(|item| r.insert(item));

    let ranim_text = Group::<VItem>::from(
        SvgItem::new(typst_svg(
            r#"
#align(center)[
    #text(10pt, font: "LXGW Bright")[Ranim]
]"#,
        ))
        .with(|text| {
            text.set_color(manim::WHITE)
                .scale_to(ScaleHint::PorportionalY(1.0))
                .put_center_on(DVec3::NEG_Y * 2.5);
        }),
    );
    let r_ranim_text = r.insert(ranim_text);

    r_logo.iter().for_each(|item| {
        r.timeline_mut(item)
            .play_with(|item| item.write().with_duration(3.0).with_rate_func(smooth));
    });
    r.timelines_mut().sync();

    let gap_ratio = 1.0 / 60.0;
    let gap = logo_width * gap_ratio;
    let scale = (logo_width - gap * 2.0) / logo_width;
    let scale = [
        dvec3(scale, 1.0, 1.0),
        dvec3(scale, scale, 1.0),
        dvec3(scale, scale, 1.0),
    ];
    let anchor = [
        Anchor::edge(-1, 0, 0),
        Anchor::edge(1, 1, 0),
        Anchor::edge(1, -1, 0),
    ];
    r_logo
        .iter()
        .chunks(2)
        .into_iter()
        .zip(scale.into_iter().zip(anchor))
        .for_each(|(chunk, (scale, anchor))| {
            let chunk = chunk.collect_array::<2>().unwrap();
            r.timeline_mut(&chunk).iter_mut().for_each(|timeline| {
                timeline.play_with(|item| {
                    item.transform(|data| {
                        data.scale_by_anchor(scale, anchor)
                            .scale_by_anchor(dvec3(0.9, 0.9, 1.0), Anchor::ORIGIN)
                            .shift(dvec3(0.0, 1.3, 0.0));
                    })
                    .with_rate_func(smooth)
                });
            });
        });
    r.timeline_mut(&r_ranim_text)
        .forward(0.5)
        .play_with(|text| {
            text.lagged(0.2, |item| {
                item.write().with_duration(2.0).with_rate_func(linear)
            })
            .with_duration(2.0)
        });
    r.timelines_mut().sync();

    r.insert_time_mark(
        r.timelines().max_total_secs(),
        TimeMark::Capture("preview.png".to_string()),
    );
    r.timelines_mut().forward(1.0);

    r_logo.iter().for_each(|r_logo_part| {
        r.timeline_mut(r_logo_part)
            .play_with(|item| item.unwrite().with_duration(3.0).with_rate_func(smooth));
    });
    r.timeline_mut(&r_ranim_text).play_with(|text| {
        text.lagged(0.0, |item| {
            item.unwrite().with_duration(3.0).with_rate_func(linear)
        })
    });
}

fn main() {
    #[cfg(not(target_arch = "wasm32"))]
    {
        #[cfg(debug_assertions)]
        pretty_env_logger::formatted_timed_builder()
            .filter(Some("ranim"), LevelFilter::Trace)
            .init();
        #[cfg(not(debug_assertions))]
        pretty_env_logger::formatted_timed_builder()
            .filter(Some("ranim"), LevelFilter::Info)
            .init();
    }

    #[cfg(feature = "app")]
    preview(ranim_logo_scene);
    #[cfg(not(feature = "app"))]
    render_scene(ranim_logo_scene);
}