import Foundation
import Maths
import simd
import JolkEngine


struct CaveScene: Scene
{
	private var colin = Colin()
	private var world = Collision()
	private var worldModel = RenderMesh<VertexPositionNormalColourTexcoord>.empty
	private var rockModel = RenderMesh<VMeshVertex>.empty, axisModel = RenderMesh<VMeshVertex>.empty
	private var rockAlbedo = Texture2D.empty, rockNormal = Texture2D.empty, axisAlbedo = Texture2D.empty
	private var skung = Quatf.init(), skungFrom = Quatf.init(), skungTo = Quatf.init()
	private var skungx: Float = 0.0
	private var axisPos = Vec3f(2.0, 0.5, 0.0)
	private var drawEdges = false

	mutating func setup(render: inout any JolkEngine.Renderer)
	{
		colin.setPosition(Vec3f(3.55475903, 0.0667395443, 0.221960306))
		colin.setAngle(Vec2f(-1.47447872, 0.0))
		skungTo = .lookAt(from: axisPos, to: colin.position + .up)
	}
	
	mutating func loadContent(content: inout JolkEngine.ContentManager) throws
	{
		let obj = try ObjReader.read(url: try content.getResource("CaveScene.obj"))
		let mesh: Mesh = try ObjLoader.read(model: obj, content: &content)
		worldModel = try content.create(mesh: mesh)
		rockModel = try content.load("rock.mesh")
		rockAlbedo = try content.load("rock.dds")
		rockNormal = try content.load("rocknorm.dds")
		axisModel = try content.load("Axis.obj.cache")
		axisAlbedo = try content.load("AxisTex.png")

		if let collision = obj.objects["Collision3D"]
		{
			world.build(obj: obj, collision: collision)
		}
	}
	
	mutating func update(deltaTime: Float)
	{
		colin.update(deltaTime: deltaTime, world: world)

		skungx = skungx + deltaTime
		if skungx >= 1
		{
			skungx = fmod(skungx, 1.0)
			skungFrom = skungTo
			skungTo = .lookAt(from: axisPos, to: colin.position + .up)
		}
		skung = skungFrom.slerp(skungTo, skungx.smoothStep())

		if let pad = GamePad.current?.state
		{
			if pad.down(.north)
			{
				axisPos += .forward * skung * deltaTime
			}
		}
		if Input.instance.keyboard.keyPressed(.c) { drawEdges = !drawEdges }
	}
	
	func draw(render: inout Renderer, deltaTime: Float, aspectRatio aspect: Float)
	{
		render.setProjection(matrix: .perspective(
			fovY: Float.rad(fromDeg: colin.fov),
			aspect: aspect, zNear: 0.1, zFar: 4000.0))
		render.setView(matrix: colin.transform)

		var env = Environment()
		let drawRanges =
		{ [render](range: any Sequence<Int>) in
			for i in range
			{
				let subMesh = worldModel.subMeshes[i]
				render.setMaterial(worldModel.materials[subMesh.material])
				render.draw(mesh: worldModel, subMesh: subMesh, environment: env)
			}
		}
		if colin.position.x < 14 { drawRanges([ 0, 1, 2, 6 ]) }
		else { drawRanges(3...5) }

		//print(Mat4f.rotate(yawPitch: colin.angle) * -Vec3f.Z)
		env.addDirectionalLight(direction: -.init(-0.6199881, 0.7049423, 0.34448668), colour: .white)
		render.setMaterial(.init(
			//specular: .init(grey: 0.5),
			specular: .white,
			gloss: 1,
			texture: axisAlbedo.id))
		render.draw(mesh: axisModel, model: .translate(axisPos) * Mat4f(quat: skung), environment: env)

		render.setMaterial(.init(
			diffuse: XnaColour.DarkGray.lighten(by: -0.1),
			//specular: .init(grey: 0.9),
			specular: .white,
			emmision: XnaColour.Green.mix(with: .black, 0.876),
			gloss: 20,
			texture: rockAlbedo.id))
		render.draw(mesh: rockModel, model: .translate(.init(27.622196, 0.8187093, -19.366903)), environment: env)

		if drawEdges { world.draw(render, position: colin.position) }
	}
}
