<script lang="ts">
	import type { Snippet } from 'svelte'

	import { T } from '@threlte/core'
	import { Environment, Grid, interactivity, PerfMonitor, PortalTarget } from '@threlte/extras'
	import { useXR } from '@threlte/xr'
	import { ShaderMaterial, Vector3 } from 'three'

	import Camera from './Camera.svelte'
	import Entities from './Entities/Entities.svelte'
	import Focus from './Focus.svelte'
	import Selected from './Selected.svelte'
	import StaticGeometries from './StaticGeometries.svelte'
	import { useFocusedObject3d } from '../hooks/useSelection.svelte'
	import { useSettings } from '../hooks/useSettings.svelte'
	import { bvh } from '../plugins/bvh.svelte'

	import hdrImage from '../assets/ferndale_studio_11_1k.hdr'
	import BatchedArrows from './BatchedArrows.svelte'
	import CameraControls from './CameraControls.svelte'
	import MeasureTool from './MeasureTool/MeasureTool.svelte'
	import PointerMissBox from './PointerMissBox.svelte'
	import { useOrigin } from './xr/useOrigin.svelte'

	interface Props {
		children?: Snippet
	}

	let { children }: Props = $props()

	const settings = useSettings()
	const focusedObject3d = useFocusedObject3d()
	const origin = useOrigin()

	const { raycaster, enabled } = interactivity({
		filter: (intersections) => {
			const match = intersections.find((intersection) => {
				return intersection.object.visible === undefined || intersection.object.visible === true
			})

			return match ? [match] : []
		},
	})

	$effect(() => {
		enabled.set(settings.current.interactionMode === 'navigate')
	})

	bvh(raycaster, () => ({ helper: false }))

	const focusedObject = $derived(focusedObject3d.current)

	const { isPresenting } = useXR()
</script>

{#if settings.current.renderStats}
	<PerfMonitor anchorX="right" />
{/if}

<Environment url={hdrImage} />

<T.Group
	position={origin.position}
	rotation.x={$isPresenting ? -Math.PI / 2 : 0}
	rotation.z={origin.rotation}
>
	<PointerMissBox />
	<MeasureTool />

	{#if focusedObject}
		<Focus object3d={focusedObject} />
	{:else}
		{#if !$isPresenting}
			<Camera position={[3, 3, 3]}>
				<CameraControls />
			</Camera>
		{/if}

		<StaticGeometries />
		<Selected />

		{#if !$isPresenting && settings.current.grid}
			<Grid
				oncreate={(ref) => {
					const material = ref.material as ShaderMaterial
					material.depthWrite = false
				}}
				raycast={() => null}
				bvh={{ enabled: false }}
				plane="xy"
				sectionColor="#333"
				infiniteGrid
				renderOrder={999}
				cellSize={settings.current.gridCellSize}
				sectionSize={settings.current.gridSectionSize}
				fadeOrigin={new Vector3()}
				fadeDistance={settings.current.gridFadeDistance}
			/>
		{/if}
	{/if}

	<T.Group attach={focusedObject ? false : undefined}>
		<PortalTarget id="world" />
		<PortalTarget />

		<Entities />
		<BatchedArrows />
	</T.Group>

	{@render children?.()}

	<T.DirectionalLight position={[3, 3, 3]} />
	<T.AmbientLight />
</T.Group>
