package ru.dbotthepony.kstarbound.defs.world

import ru.dbotthepony.kommons.vector.Vector2i
import ru.dbotthepony.kstarbound.defs.PerlinNoiseParameters
import ru.dbotthepony.kstarbound.json.builder.JsonFactory
import ru.dbotthepony.kstarbound.util.random.AbstractPerlinNoise
import ru.dbotthepony.kstarbound.util.random.random
import java.util.random.RandomGenerator
import kotlin.math.PI
import kotlin.math.cos
import kotlin.math.sin

@JsonFactory
data class BlockNoiseConfig(
	val horizontalNoise: PerlinNoiseParameters,
	val verticalNoise: PerlinNoiseParameters,
	val noise: PerlinNoiseParameters,
) {
	fun build(random: RandomGenerator): BlockNoise {
		return BlockNoise(
			AbstractPerlinNoise.of(horizontalNoise).also { it.init(random.nextLong()) },
			AbstractPerlinNoise.of(verticalNoise).also { it.init(random.nextLong()) },
			AbstractPerlinNoise.of(noise).also { it.init(random.nextLong()) },
			AbstractPerlinNoise.of(noise).also { it.init(random.nextLong()) },
		)
	}

	fun build(seed: Long) = build(random(seed))
}

@JsonFactory
data class BlockNoise(
	val horizontalNoise: AbstractPerlinNoise,
	val verticalNoise: AbstractPerlinNoise,
	val xNoise: AbstractPerlinNoise,
	val yNoise: AbstractPerlinNoise,
) {
	fun apply(x: Int, y: Int, width: Int, height: Int): Vector2i {
		val angle = (x.toDouble() / width.toDouble()) * 2.0 * PI

		// eek?
		val xc = sin(angle) / (2.0 * PI) * width
		val zc = cos(angle) / (2.0 * PI) * width

		return Vector2i(
			(x + horizontalNoise[y.toDouble()] + xNoise[xc, y.toDouble(), zc]).toInt(),
			(y + verticalNoise[xc, zc] + yNoise[xc, y.toDouble(), zc]).toInt().coerceIn(0, height),
		)
	}
}
