/*
    Hurry Curry! - a game about cooking
    Copyright 2024 metamuffin
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, version 3 of the License only.
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.
    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see .
*/
pub mod misc;
pub mod sprite;
use hurrycurry_protocol::glam::Vec2;
use sdl2::{
    pixels::PixelFormatEnum,
    rect::{FRect, Rect},
    render::{BlendMode, Canvas, Texture, TextureAccess, TextureCreator},
    video::{Window, WindowContext},
};
use sprite::SpriteDraw;
use std::collections::HashMap;
pub struct SpriteRenderer<'a> {
    metadata: AtlasLayout,
    pub size: Vec2,
    texture: Texture<'a>,
    round: bool,
    view_scale: Vec2,
    view_offset: Vec2,
    sprites: Vec,
}
pub type AtlasLayout = HashMap;
impl<'a> SpriteRenderer<'a> {
    pub fn init(texture_creator: &'a TextureCreator) -> Self {
        let palette = include_str!("../../assets/palette.csv")
            .split('\n')
            .filter(|l| !l.is_empty())
            .map(|s| {
                let mut toks = s.split(",");
                (
                    toks.next().unwrap().chars().next().unwrap(),
                    [
                        toks.next().unwrap().parse::().unwrap(),
                        toks.next().unwrap().parse::().unwrap(),
                        toks.next().unwrap().parse::().unwrap(),
                        toks.next().unwrap().parse::().unwrap(),
                    ],
                )
            })
            .collect::>();
        let mut texels = vec![255; 1024 * 1024 * 4];
        for (y, line) in include_str!("../../assets/atlas.ta").lines().enumerate() {
            if line.is_empty() {
                continue;
            }
            for (x, char) in line.chars().enumerate() {
                let color = palette.get(&char).unwrap();
                texels[(y * 1024 + x) * 4] = color[3];
                texels[(y * 1024 + x) * 4 + 1] = color[2];
                texels[(y * 1024 + x) * 4 + 2] = color[1];
                texels[(y * 1024 + x) * 4 + 3] = color[0];
            }
        }
        let mut texture = texture_creator
            .create_texture(
                Some(PixelFormatEnum::RGBA8888),
                TextureAccess::Streaming,
                1024,
                1024,
            )
            .unwrap();
        texture.update(None, &texels, 1024 * 4).unwrap();
        texture.set_blend_mode(BlendMode::Blend);
        let metadata = include_str!("../../assets/atlas.meta.csv")
            .lines()
            .filter(|l| !l.is_empty())
            .map(|l| {
                let mut toks = l.split(",");
                let x: i32 = toks.next().unwrap().parse().unwrap();
                let y: i32 = toks.next().unwrap().parse().unwrap();
                let w: u32 = toks.next().unwrap().parse().unwrap();
                let h: u32 = toks.next().unwrap().parse().unwrap();
                let name = toks.next().unwrap().to_string();
                (name, Rect::new(x, y, w, h))
            })
            .collect::>();
        Self {
            round: true,
            texture,
            size: Vec2::ONE,
            metadata,
            sprites: vec![],
            view_offset: Vec2::ZERO,
            view_scale: Vec2::ZERO,
        }
    }
    pub fn set_view(&mut self, offset: Vec2, scale: f32) {
        self.view_offset = offset;
        self.view_scale = Vec2::new(32., 24.) * scale;
    }
    pub fn get_scale(&self) -> Vec2 {
        self.view_scale
    }
    #[inline]
    pub fn atlas_layout(&self) -> &HashMap {
        &self.metadata
    }
    pub fn set_modulation(&mut self, r: u8, g: u8, b: u8, a: u8) {
        self.texture.set_alpha_mod(a);
        self.texture.set_color_mod(r, g, b);
    }
    pub fn reset_modulation(&mut self) {
        self.set_modulation(255, 255, 255, 255)
    }
    pub fn draw_world(&mut self, sprite: SpriteDraw) {
        self.sprites.push(SpriteDraw {
            tint: sprite.tint,
            z_order: sprite.z_order,
            src: sprite.src,
            dst: FRect::new(
                (sprite.dst.x + self.view_offset.x) * self.view_scale.x,
                (sprite.dst.y + self.view_offset.y) * self.view_scale.y,
                sprite.dst.w * self.view_scale.x,
                sprite.dst.h * self.view_scale.y,
            ),
        })
    }
    pub fn submit(&mut self, canvas: &mut Canvas) {
        self.sprites.sort();
        for SpriteDraw { src, dst, tint, .. } in self.sprites.drain(..) {
            self.texture.set_color_mod(tint[0], tint[1], tint[2]);
            self.texture.set_alpha_mod(tint[3]);
            canvas.copy_f(&self.texture, src, dst).unwrap();
        }
    }
}