use crate::effects::star_field;
use crate::slide::Slide;
use crate::slide_show_config::Context;
use config::Config;
use macroquad::color::{BLACK, WHITE};
use macroquad::file::load_file;
use macroquad::math::Vec2;
use macroquad::prelude::{Texture2D, clear_background, load_texture, draw_texture, draw_texture_ex, DrawTextureParams};
use macroquad::window::{screen_height, screen_width};
use serde::Deserialize;
use std::path::{Path, PathBuf};

#[derive(Debug, Deserialize)]
pub struct StandardSlideConfig {
    title: String,
    body: String,
    image: Option<PathBuf>,
}

impl StandardSlideConfig {
    pub fn new(src: &str) -> Result<Self, config::ConfigError> {
        let cfg = Config::builder()
            .add_source(config::File::from_str(src, config::FileFormat::Toml))
            .build()?;

        cfg.try_deserialize()
    }
}

#[derive(Debug)]
pub struct StandardSlide {
    cfg: StandardSlideConfig,
    image: Option<Texture2D>,
}

impl StandardSlide {
    pub async fn new(cfg_path: &Path) -> Box<Self> {
        let cfg_bytes = load_file(cfg_path.to_str().unwrap()).await.unwrap();
        let cfg_str = String::from_utf8(cfg_bytes).unwrap();
        let cfg = StandardSlideConfig::new(&cfg_str).unwrap();

        let image = if let Some(image_path) = &cfg.image {
            Some(load_texture(image_path.to_str().unwrap()).await.unwrap())
        } else {
            None
        };

        Box::new(Self { cfg, image })
    }
}

impl Slide for StandardSlide {
    fn display(&mut self, ctx: &Context<'_>) {
        clear_background(BLACK);
        star_field();

        let title_pos = Vec2::new(screen_width() * 0.5, screen_height() * 0.10);
        let info = ctx
            .slide_show_theme
            .heading_config
            .draw_text(&self.cfg.title, title_pos);

        let body_pos = Vec2::new(
            screen_width() * 0.05,
            screen_height() * 0.33 + info.text_dimensions.height,
        );
        ctx.slide_show_theme.body_config.draw_text_box(
            &self.cfg.body,
            body_pos,
            Vec2::new(screen_width() * 0.5, screen_height() * 0.8),
        );


        if let Some(image) = &self.image {
            let size = image.size();
            let image_center_pos = Vec2::new(screen_width() * 0.75, screen_height() * 0.5);

            let target_image_size = Vec2::new(screen_width() * 0.33, screen_height() * 0.66);

            let scale = f32::min(target_image_size.x / size.x, target_image_size.y / size.y);

            let new_image_size = size * scale;

            let image_pos = image_center_pos - new_image_size * 0.5;

            draw_texture_ex(image, image_pos.x, image_pos.y, WHITE, DrawTextureParams {
                dest_size: Some(new_image_size),
                ..Default::default()
            });
        }
    }
}
