//
//  SceneReconstructionViewController.swift
//  HeiseARKit3
//
//  Created by Gero Gerber on 26.03.20.
//  Copyright © 2020 Gero Gerber. All rights reserved.
//

import ARKit
import RealityKit
import UIKit

class SceneReconstructionViewController: UIViewController {

	@IBOutlet var arView: ARView!
	
	let sphereRadius: Float = 0.1
	let sphereMass: Float = 0.45
	
	var cameraAnchor: AnchorEntity!
	
	override func viewDidLoad() {
        super.viewDidLoad()

        guard ARWorldTrackingConfiguration.isSupported &&
			ARWorldTrackingConfiguration.supportsSceneReconstruction(.meshWithClassification) else {
            fatalError("ARWorldTrackingConfiguration with Scene-Reconstruction .meshWithClassification is not supported on this device!")
        }
		
		let config = ARWorldTrackingConfiguration()
		config.sceneReconstruction = .mesh
		config.planeDetection = .horizontal
		config.environmentTexturing = .automatic
		
		arView.automaticallyConfigureSession = true
		arView.debugOptions.insert(.showSceneUnderstanding)
		arView.environment.sceneUnderstanding.options.insert(.occlusion)
		arView.environment.sceneUnderstanding.options.insert(.physics)
		arView.environment.sceneUnderstanding.options.insert(.receivesLighting)
		arView.session.run(config, options: .resetTracking)
		
		cameraAnchor = AnchorEntity(world: [0, 0, 0])
		
		arView.scene.addAnchor(cameraAnchor)
    }
    
	@IBAction func onTap(_ sender: UITapGestureRecognizer) {
		guard let frame = arView.session.currentFrame else { return }
		
		var impulseDirection = frame.camera.transform.zAxis()
		impulseDirection = normalize(impulseDirection) * -2
		let position = frame.camera.transform.position()
		
		let mesh = MeshResource.generateSphere(radius: sphereRadius)
		let shape = ShapeResource.generateSphere(radius: sphereRadius)
		var material = SimpleMaterial()
		material.baseColor = try! MaterialColorParameter.texture(TextureResource.load(named: "balldimpled.png"))
		material.metallic = MaterialScalarParameter(floatLiteral: 0.0)
		material.roughness = MaterialScalarParameter(floatLiteral: 0.8)
		material.tintColor = UIColor.white
		
		let sphere = ModelEntity(mesh: mesh, materials: [material])
		sphere.position = position
		sphere.physicsBody = PhysicsBodyComponent(shapes: [shape], mass: sphereMass)
		sphere.collision = CollisionComponent(shapes: [shape])
		
		cameraAnchor.addChild(sphere)
		sphere.applyLinearImpulse(impulseDirection, relativeTo: sphere)
	}
	
	@IBAction func toggleCameraBackground(_ sender: UISwitch) {
		if sender.isOn {
			arView.environment.background = .cameraFeed()
		} else {
			arView.environment.background = .color(.black)
		}
	}
	
	@IBAction func toggleDebugMesh(_ sender: UISwitch) {
		if sender.isOn {
			arView.debugOptions.insert(.showSceneUnderstanding)
		} else {
			arView.debugOptions.remove(.showSceneUnderstanding)
		}
	}
}

extension ARMeshGeometry {
    func classificationOf(faceWithIndex index: Int) -> ARMeshClassification {
        guard let classification = classification else { return .none }
        let classificationAddress = classification.buffer.contents().advanced(by: index)
        let classificationValue = Int(classificationAddress.assumingMemoryBound(to: UInt8.self).pointee)
        return ARMeshClassification(rawValue: classificationValue) ?? .none
    }
}

extension UIColor {
	static func random() -> UIColor {
		return UIColor(red: .random(in: 0...1), green: .random(in: 0...1), blue: .random(in: 0...1), alpha: 1.0)
	}
}

extension simd_float4x4 {
	func position() -> SIMD3<Float> {
		return [columns.3.x, columns.3.y, columns.3.z]
	}
	
	func zAxis() -> SIMD3<Float> {
		return [columns.2.x, columns.2.y, columns.2.z]
	}
}
