-- Track 1

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local CollectionService = game:GetService("CollectionService")
local EventSequencer = require(ReplicatedStorage:WaitForChild("EventSequencer"))
local BouncePlatforms = require(ReplicatedStorage:WaitForChild("BouncePlatforms"))

local GetCurrentSceneEnvironment = EventSequencer.getCurrentSceneEnvironment
local Schema = EventSequencer.createSchema()

local performerAnimations = require(script.PerformerAnimations)

local Environment = nil
local ServerEnvironment = nil
local MainAudio = nil
local Performer = nil
local StageSpotlights = {}
local PerformerRootPart = nil
local PerformerRootPartBaseCFrame = CFrame.new(0, 0, 0)
local rng = Random.new()

function enableBouncyPads()
	for _, part in pairs(CollectionService:GetTagged("Bouncy")) do
		BouncePlatforms.new(part, {
			debounce = 0.2,
			bounceVector = Vector3.new(0, 1, 0),
			bounceForce = 150,
		})
	end
	BouncePlatforms:enable()
end

local function emitChanceFromTagged(tagName, chance, newLifetime)
	for _, emitter in pairs(CollectionService:GetTagged(tagName)) do
		if rng:NextNumber(0, 1) <= chance then
			if newLifetime then
				emitter.Lifetime = newLifetime
			end
			emitter:Emit(1)
		end
	end
end

local function setTaggedObjectsEnabled(tagName, enabled)
	for _, emitter in pairs(CollectionService:GetTagged(tagName)) do
		emitter.Enabled = enabled
	end
end

local function schemaSetTaggedObjectsEnabled(timeStamp, tagName, enabled)
	Schema:schedule({
		SyncToAudio = {
			Audio = MainAudio,
			StartAtAudioTimes = { timeStamp },
			Skippable = true,
		},
		OnStart = function()
			setTaggedObjectsEnabled(tagName, enabled)
		end,
	})
end

local function setStageSpotlightEnabled(lightIndex, enabled)
	local lens = StageSpotlights["i" .. lightIndex] -- Get cached object
	if not lens and ServerEnvironment then
		local stageSpotlights = ServerEnvironment:FindFirstChild("StageSpotlights", true)
		if stageSpotlights then
			local spotLight = stageSpotlights:FindFirstChild("SpotLight" .. lightIndex)
			if spotLight then
				lens = spotLight:FindFirstChild("lens")
				StageSpotlights["i" .. lightIndex] = lens -- Cache object for quick access
			end
		end
	end

	if lens then
		lens.Material = enabled and Enum.Material.Neon or Enum.Material.Plastic
		lens.Color = enabled and Color3.fromRGB(175, 221, 255) or Color3.fromRGB(80, 148, 193)
		local beam = lens:FindFirstChild("LightBeam")
		if beam then
			beam.Enabled = enabled
		end
		local light = lens:FindFirstChild("SpotLight")
		if light then
			light.Enabled = enabled
		end
	end
end

local function schemaSetStageSpotlightIndexesEnabled(timeStamp, lightIndexList, enabled)
	Schema:schedule({
		SyncToAudio = {
			Audio = MainAudio,
			StartAtAudioTimes = { timeStamp },
			Skippable = true,
		},
		OnStart = function()
			for _, lightIndex in pairs(lightIndexList) do
				setStageSpotlightEnabled(lightIndex, enabled)
			end
		end,
	})
end

local function schemaRotateStageLights(startTime, endTime, lightChangeRate, startLightIndex, direction)
	direction = direction or -1
	lightChangeRate = lightChangeRate or 0.5
	startLightIndex = startLightIndex or 1
	local numLightChanges = math.max(1, math.floor((endTime - startTime) / lightChangeRate))
	for i = 0, numLightChanges do
		local timeStamp = startTime + i * lightChangeRate
		local onLightIndex = ((startLightIndex + i * direction - 1) % 8) + 1
		local offLightIndex = ((startLightIndex + (i - 1) * direction - 1) % 8) + 1
		schemaSetStageSpotlightIndexesEnabled(timeStamp, { onLightIndex }, true)
		schemaSetStageSpotlightIndexesEnabled(timeStamp, { offLightIndex }, false)
	end
end

local lightsWaveMapIndexes = { { 2 }, { 1, 3 }, { 4, 8 }, { 5, 7 }, { 6 } }
local function schemaWaveStageLights(startTime, endTime, changeRate, startMapIndex, direction)
	direction = direction or 1
	changeRate = changeRate or 0.333
	startMapIndex = startMapIndex or 1
	local numLightChanges = math.max(1, math.floor((endTime - startTime) / changeRate))
	for i = 0, numLightChanges do
		local timeStamp = startTime + i * changeRate
		local onLightMapIndex = ((startMapIndex + i * direction - 1) % 5) + 1
		local offLightMapIndex = ((startMapIndex + (i - 1) * direction - 1) % 5) + 1
		schemaSetStageSpotlightIndexesEnabled(timeStamp, lightsWaveMapIndexes[onLightMapIndex], true)
		schemaSetStageSpotlightIndexesEnabled(timeStamp, lightsWaveMapIndexes[offLightMapIndex], false)
	end
end

Schema.OnSetup = function()
	Environment = GetCurrentSceneEnvironment()
	ServerEnvironment = EventSequencer.getCurrentServerEnvironmentFromClient()

	Performer = Environment:WaitForChild("Nitro")
	PerformerRootPart = Performer:WaitForChild("HumanoidRootPart")
	PerformerRootPartBaseCFrame = PerformerRootPart.CFrame
	
	enableBouncyPads()

	StageSpotlights = {}
end

Schema.OnRun = function()
	MainAudio = Schema:audio({
		StartTime = 0,
		SoundId = "rbxassetid://1838673350",
	})

	performerAnimations(Schema, MainAudio, Performer)

	schemaSetStageSpotlightIndexesEnabled(0, { 1, 2, 3, 4, 5, 6, 7, 8 }, false)
	schemaSetTaggedObjectsEnabled(0, "DistantFog", true)
	schemaSetTaggedObjectsEnabled(0, "BurstFog", false)

	schemaRotateStageLights(2, 15.5, 0.5, 8, -1)

	schemaSetStageSpotlightIndexesEnabled(16, { 1, 2, 3 }, true)
	schemaSetStageSpotlightIndexesEnabled(16, { 4, 5, 6, 7, 8 }, false)

	schemaSetStageSpotlightIndexesEnabled(32, { 1, 2, 3 }, false)

	schemaSetStageSpotlightIndexesEnabled(39, { 4, 5, 6, 7, 8 }, true)

	-- Raise the performer
	local raisePerformer = Schema:tween({	-- There are currently problems when seeking while tweening a cframe
		StartTimes = { 39 },
		Tween = {
			Object = PerformerRootPart,
			Info = TweenInfo.new(5.8, Enum.EasingStyle.Quad, Enum.EasingDirection.InOut),
			Properties = {
				CFrame = CFrame.new(0, 6, 0) * PerformerRootPartBaseCFrame,
			},
		},
	})

	schemaSetStageSpotlightIndexesEnabled(42, { 4, 5, 6, 7, 8 }, false)
	schemaSetStageSpotlightIndexesEnabled(42, { 1, 2, 3 }, true)
	schemaSetTaggedObjectsEnabled(42, "DistantFog", false)

	-- Drop the performer
	local dropPerformer = Schema:tween({	-- There are currently problems when seeking while tweening a cframe
		StartTimes = { 45 },
		Tween = {
			Object = PerformerRootPart,
			Info = TweenInfo.new(0.5, Enum.EasingStyle.Quad, Enum.EasingDirection.Out),
			Properties = {
				CFrame = PerformerRootPartBaseCFrame,
			},
		},
	})

	-- 46 First drop

	schemaSetStageSpotlightIndexesEnabled(44.99, { 1, 2, 3, 4, 5, 6, 7, 8 }, false)
	schemaWaveStageLights(45, 58, 0.2, 5, -1)
	schemaSetTaggedObjectsEnabled(45.33, "BurstFog3", true)
	schemaSetTaggedObjectsEnabled(45.66, "BurstFog2", true)
	schemaSetTaggedObjectsEnabled(46, "BurstFog1", true)

	local smallSpeakerSoundwaveParticles =
		Schema:interval({ -- Speaker sound wave particles tied to sound intensity (Small)
			SyncToAudio = {
				StartAtAudioTime = 0,
				EndAtAudioTime = 147,
				Audio = MainAudio,
			},
			Frequency = 0.5,
			OnInterval = function()
				local intensity = MainAudio.CurrentSoundIntensityRatio
				emitChanceFromTagged("SpeakerParticles3", intensity, NumberRange.new(0.1 + 1 - intensity))
			end,
		})

	local LargeSpeakerSoundwaveParticles =
		Schema:interval({ -- Speaker sound wave particles tied to sound intensity (Large)
			SyncToAudio = {
				StartAtAudioTime = 46,
				EndAtAudioTime = 147,
				Audio = MainAudio,
			},
			Frequency = 0.5,
			OnInterval = function()
				local intensity = MainAudio.CurrentSoundIntensityRatio
				emitChanceFromTagged("SpeakerParticles2", intensity, NumberRange.new(0.3 + 1 - intensity))
			end,
		})

	local mediumSpeakerSoundwaveParticles =
		Schema:interval({ -- Speaker sound wave particles tied to sound intensity	(Medium)
			SyncToAudio = {
				StartAtAudioTime = 50,
				EndAtAudioTime = 147,
				Audio = MainAudio,
			},
			Frequency = 0.5,
			OnInterval = function()
				local intensity = MainAudio.CurrentSoundIntensityRatio
				emitChanceFromTagged("SpeakerParticles1", intensity, NumberRange.new(0.1 + 1 - intensity))
			end,
		})

	local smokeBursts = Schema:interval({ -- Smoke burst emitters tied to sound intensity
		SyncToAudio = {
			StartAtAudioTime = 50,
			EndAtAudioTime = 147,
			Audio = MainAudio,
		},
		Frequency = 0.1,
		OnInterval = function()
			local intensity = MainAudio.CurrentSoundIntensityRatio
			setTaggedObjectsEnabled("BurstFog3", intensity > 0.35)
			setTaggedObjectsEnabled("BurstFog2", intensity > 0.55)
			setTaggedObjectsEnabled("BurstFog1", intensity > 0.75)
		end,
	})

	schemaRotateStageLights(58, 68, 0.2, 6, -1)

	schemaSetStageSpotlightIndexesEnabled(68.1, { 1, 2, 3, 4, 5, 6, 7, 8 }, true)

	-- Raise the performer
	local raisePerformerQuickly = Schema:tween({	-- There are currently problems when seeking while tweening a cframe
		StartTimes = { 67.75 },
		Tween = {
			Object = PerformerRootPart,
			Info = TweenInfo.new(0.5, Enum.EasingStyle.Quad, Enum.EasingDirection.Out),
			Properties = {
				CFrame = CFrame.new(0, 6, 0) * PerformerRootPartBaseCFrame,
			},
		},
	})

	local dropPerformerQuickly = Schema:tween({
		StartTimes = { 68.25 },
		Tween = {
			Object = PerformerRootPart,
			Info = TweenInfo.new(0.5, Enum.EasingStyle.Quad, Enum.EasingDirection.In),
			Properties = {
				CFrame = PerformerRootPartBaseCFrame,
			},
		},
	})

	schemaRotateStageLights(71, 88, 0.2, 8, 1)

	schemaSetStageSpotlightIndexesEnabled(88.1, { 1, 2, 3, 4, 5, 6, 7, 8 }, true)

	schemaWaveStageLights(90, 105, 0.2, 5, -1)

	-- Pick up the pace
	schemaWaveStageLights(107, 122.5, 0.1, 5, 1)

	-- 123 go mellow
	schemaSetStageSpotlightIndexesEnabled(123, { 1, 2, 3, 4, 5, 6, 7, 8 }, false)
end

Schema.OnEndScene = function()
	StageSpotlights = {}
end

return Schema