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

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

#[derive(Debug, Deserialize, Serialize)]
pub struct AudioTrackRequest {
    api_key: String,
    voice: String,
    phrase: String,
}

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

impl StandardSlide {
    pub async fn new(cfg: StandardSlideConfig, asset_path: &Path) -> Box<Self> {
        let image = if let Some(image_path) = &cfg.image {
            let image_path = asset_path.join(image_path);
            Some(load_texture(image_path.to_str().unwrap()).await.unwrap())
        } else {
            None
        };

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

    pub fn audio_track(&mut self, api: &FrenApiConfig) {
        if !self.audio_started {
            self.audio_started = true;

            if let Some(track) = &self.cfg.audio_track
                && let Some(voice) = &self.cfg.voice
            {
                let request = AudioTrackRequest {
                    api_key: api.api_key.clone(),
                    voice: voice.to_string(),
                    phrase: track.to_string(),
                };

                reqwest::blocking::Client::new()
                    .post(&api.api_addr)
                    .json(&request)
                    .send()
                    .unwrap();
            }
        }
    }
}

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

        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()
                },
            );
        }
    }
}
