// Copyright Marcus Del Favero 2025
// Licensed under the GNU AGPLv3 with an exception, see `README.md` for details
use std::{iter, num::NonZeroU32, path::PathBuf};

use glam::UVec2;

use super::{Vm, Op};

pub struct MazeParams {
	pub size: UVec2,
	pub seed: u64,
	pub wall_thickness: NonZeroU32,
	pub open_thickness: NonZeroU32,
}

pub fn random_mazes() -> impl Iterator<Item = MazeParams> {
	iter::repeat_with(|| {
		MazeParams {
			size: rand::random::<UVec2>() % 50 + 1,
			seed: rand::random::<u64>(),
			wall_thickness: (rand::random::<u32>() % 10 + 1).try_into().unwrap(),
			open_thickness: (rand::random::<u32>() % 10 + 1).try_into().unwrap(),
		}
	})
}

// Individual examples known to previously fail
#[test]
fn example1() {
	maze_connected(MazeParams {
		size: UVec2::splat(50),
		seed: 0,
		wall_thickness: 2.try_into().unwrap(),
		open_thickness: 3.try_into().unwrap(),
	});
}

#[test]
fn example2() {
	maze_connected(MazeParams {
		size: UVec2::splat(43),
		seed: 7226261265836791453,
		wall_thickness: 1.try_into().unwrap(),
		open_thickness: 1.try_into().unwrap(),
	});
}

#[test]
fn property_tests() {
	random_mazes().take(50000).for_each(maze_connected);
}

fn maze_connected(params: MazeParams) {
	let mut vm = Vm::new(params.size, PathBuf::new());
	vm.run(&[
		Op::Maze {
			seed: params.seed,
			wall_thickness: params.wall_thickness,
			open_thickness: params.open_thickness,
			open_prob: 0.0,
			close_prob: 0.0,
		},
		Op::Duplicate(0),
		Op::FillHoles,
	]).unwrap();

	assert!(vm.stack.len() == 2);
	assert!(vm.stack[0] == vm.stack[1]);
}
