// Copyright Marcus Del Favero 2025
// Licensed under the GNU AGPLv3 with an exception, see `README.md` for details
mod perlin;

use std::array;

use rand::SeedableRng;
use rand_chacha::ChaCha20Rng;
use png::ColorType;

use perlin::{PerlinNoiseMap, PerlinConfig};

use super::{image::Image, layer::Layer};

use crate::utils;

const PATH: &str = "../data/textures/clouds.png";
const SIZE: usize = 1024;
const STEPS: usize = 9;

fn image(seed: u64, scale_pow: f32) -> Vec<u8> {
	let mut layer = Layer::<f32>::new(SIZE, SIZE);

	let map = PerlinNoiseMap::new(SIZE, SIZE, ChaCha20Rng::seed_from_u64(seed + 189371 /* Random number */));

	// Inspired by https://wwwtyro.net/2016/10/22/2D-space-scene-procgen.html
	for y in 0..SIZE {
		for x in 0..SIZE {
			let mut point = 0.0;
			let (mut fx, mut fy) = (x as f32, y as f32);
			for i in (0..STEPS).rev() {
				let scale = 1 << i;
				let config = PerlinConfig { scale };
				let fscale = scale as f32;

				let d = (map.with_config(&config).get(fx, fy) * 0.5 + 0.5) * fscale;

				fx += d;
				fy += d;

				point += (map.with_config(&config).get(fx, fy) * 0.5 + 0.5) * fscale.powf(scale_pow);
			}

			layer.pixel(x, y, (point + 0.375).powi(6));
		}
	}

	layer.normalise();

	Image::from(layer).flip_vertical(ColorType::Grayscale).pixels.into_vec()
}

pub fn generate() {
	const COUNT: usize = 3;
	const CHANNELS: usize = 2; // NOTE: If this is changed, make sure to change the output format

	if utils::exists(PATH) { return; }

	let mut pixels: Vec<u8> = Vec::with_capacity(SIZE * SIZE * CHANNELS * COUNT);
	for i in 0..COUNT {
		let channels: [Vec<u8>; CHANNELS] = array::from_fn(|j| image((i * CHANNELS + j) as u64, 1.0 - i as f32 * 0.09375));
		for i in 0..SIZE * SIZE {
			for channel in &channels {
				pixels.push(channel[i]);
			}
		}
	}

	Image {
		width: SIZE,
		height: SIZE * COUNT,
		pixels: pixels.into_boxed_slice(),
	}.save(PATH, ColorType::GrayscaleAlpha);
}
