local Module = {}

local TweenService = game:GetService("TweenService")
local Players = game:GetService("Players")
local ServerStorage = game:GetService("ServerStorage")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local LocalRemotes = ReplicatedStorage:WaitForChild("LocalRemotes")

local MapsFolder = ServerStorage:WaitForChild("Maps")
local Workspace = game:GetService("Workspace")
local MAP = workspace:WaitForChild("Map")
local LDM = workspace:WaitForChild("LDM")
local MorphModule = require(ServerStorage.Assets.Morphs.MorphModule)

local Spawns = MAP:WaitForChild("CurrentMap"):WaitForChild("Spawns")
local GameSettings = workspace:WaitForChild("GameSettings")
local Seconds = GameSettings.RoundTime.Seconds
local Decrease = Seconds.Parent.Decrease
local CharactersFolder = workspace.Characters
local EnemyUI = script.EnemyUI
local PlayerUI = script.InformationUI

local HidersFolder = GameSettings:WaitForChild("Humans")

local SeekersAmounts = {1, 1, 2, 2, 3}
local IntermissionTime = 40
local SelectingTime = 15
local MatchTime = 480

local SeekerAura = ServerStorage:WaitForChild("Assets"):WaitForChild("Character"):WaitForChild("Auras"):WaitForChild("Seekers")

local Seekers = {}
local FirstSeeker
local SecondSeeker
local ThirdSeeker

Decrease:GetPropertyChangedSignal("Value"):Connect(function()	
	Seconds.TimeHandle.Enabled = Decrease.Value
end)

local function SelectRandomMap()
	local Maps = MapsFolder:GetChildren()
	if #Maps == 0 then
		warn("No maps found")
		return
	end

	local Index = math.random(1, #Maps)
	local SelectedMap = Maps[Index]
	local CurrentMap = workspace.Map:FindFirstChild("CurrentMap")

	if CurrentMap then
		CurrentMap.Name = CurrentMap:FindFirstChild("DefaultName").Value
		CurrentMap.Parent = MapsFolder
	end

	while workspace.Map:FindFirstChild("CurrentMap") do
		task.wait(0.5)
	end

	print("Selected map: " .. SelectedMap.Name)
	SelectedMap.Parent = workspace.Map
	SelectedMap.Name = "CurrentMap"
end


local function ApplyMorph(Character, Gender)
	MorphModule:init()
	MorphModule:ApplyModel(Character, Character, Gender, false)
end

local function RemoveMorph(Character)
	MorphModule:RemoveModel(Character, Character)
end

local function ModeSelection()
	print("Selection Mode: ")
	Decrease.Value = false
	GameSettings.GameStatus.Value = "SelectingMode"
	task.wait(2)
	ReplicatedStorage.LocalRemotes.Visual.Selection:FireAllClients(true)
	Seconds.Value = 15
	task.wait(0.5)
	Decrease.Value = true
	Seconds:GetPropertyChangedSignal("Value"):Connect(function()
		if Seconds.Value ~= 0 then return end
		if GameSettings.GameStatus.Value == "SelectingMode" then
			ReplicatedStorage.LocalRemotes.Visual.Selection:FireAllClients(false)
			GameSettings.GameStatus.Value = ""
		end
	end)
end

local function ShuffleTable(t)
	local rand = math.random 
	assert(t, "expected a table got nil")
	for i = #t, 2, -1 do
		local j = rand(i)
		t[i], t[j] = t[j], t[i]
	end
end

local function SelectSeeker()
	if GameSettings.GameStatus.Value ~= "" then 
		return 
	end

	Seekers = {} 

	Seconds.Value = SelectingTime
	Decrease.Value = true
	GameSettings.GameStatus.Value = "Choosing"

	local PlaceHolder = LDM.Intro
	local SeekersFolder = GameSettings:WaitForChild("Seekers")
	local SeekersAmount
	local Selected = false

	repeat
		local NumSelected = #Seekers
		if NumSelected >= 2 and NumSelected <= 4 then
			SeekersAmount = 1
			SelectingTime = 15
		elseif NumSelected >= 5 and NumSelected <= 12 then
			SeekersAmount = 2
			SelectingTime = 26
		elseif NumSelected >= 13 and NumSelected <= 20 then
			SeekersAmount = 3
			SelectingTime = 34
		else
			SeekersAmount = 1
			SelectingTime = 15
		end

		local Potential = CharactersFolder:GetChildren()
		local PlayerSeekers = {}
		local DummySeekers = {}

		for _, Model in ipairs(Potential) do
			if Players:GetPlayerFromCharacter(Model) then
				table.insert(PlayerSeekers, Model)
			else
				table.insert(DummySeekers, Model)
			end
		end

		ShuffleTable(PlayerSeekers)
		ShuffleTable(DummySeekers)

		for i = 1, SeekersAmount do
			local model
			if i == 1 and #PlayerSeekers > 0 then
				model = table.remove(PlayerSeekers, 1)
			else
				local Remaining = #PlayerSeekers > 0 and PlayerSeekers or DummySeekers
				model = table.remove(Remaining, 1)
			end

			model.Parent = SeekersFolder
			table.insert(Seekers, model)

			if i == 1 then
				FirstSeeker = model
			elseif i == 2 then
				SecondSeeker = model
			elseif i == 3 then
				ThirdSeeker = model
			end

			print("SEEKER NUMBER: " .. i .. " - NAME " .. model.Name)
		end

		task.wait(1)

		if #Seekers == SeekersAmount then
			Selected = true
		end
	until Selected

	for i, model in ipairs(Seekers) do
		local dummy = PlaceHolder:FindFirstChild(tostring(i))
		if dummy then
			local Player = Players:GetPlayerFromCharacter(model)
			if Player then
				local success, humanoidDescription = pcall(function()
					return Players:GetHumanoidDescriptionFromUserId(Player.UserId)
				end)

				if success and dummy:FindFirstChild("Humanoid") then
					dummy.Humanoid:ApplyDescription(humanoidDescription)
					if Player.Data.Gender.Value == "F" then
						RemoveMorph(dummy)
						task.wait(0.2)
						ApplyMorph(dummy, "Female")
					else
						RemoveMorph(dummy)
						task.wait(0.2)
						ApplyMorph(dummy, Player.Data.Gender.Value)
					end

					dummy.Torso:GetPropertyChangedSignal("Color"):Connect(function()
						repeat task.wait() until dummy:FindFirstChild("M")
						dummy:FindFirstChild("M").NewModel.Color = dummy.Torso.Color
					end)
				else
					warn("Failed to get HumanoidDescription or apply it for player " .. Player.Name .. ": " .. tostring(humanoidDescription))
				end
			else
				warn("Player not found for character " .. model.Name)
			end
		end
	end

	task.delay(5, function()
		local SeekersFolder = GameSettings:WaitForChild("Seekers")
		local HidersFolder = GameSettings:WaitForChild("Humans")

		local numSeekers = #SeekersFolder:GetChildren()

		for _, seeker in ipairs(SeekersFolder:GetChildren()) do
			local player = Players:GetPlayerFromCharacter(seeker)
			if player then
				task.wait(1)
				LocalRemotes.Visual.CharacterCamera:FireClient(player, numSeekers, table.unpack(Seekers))
			end
		end

		for _, hider in ipairs(workspace.Characters:GetChildren()) do
			local player = Players:GetPlayerFromCharacter(hider)
			if player then
				task.wait(1)
				LocalRemotes.Visual.CharacterCamera:FireClient(player, numSeekers, table.unpack(Seekers))
			end
		end
	end)

	task.wait(SelectingTime)
	Seconds.Value = 0
	Decrease.Value = false
	GameSettings.GameStatus.Value = "Prepare"
	local SeekerSpawn = MAP:WaitForChild("CurrentMap"):WaitForChild("SeekerSpawn").SpawnLocation
	SeekerSpawn.Transparency = 0
	SeekerSpawn.Information.Enabled = true
end

function Module.EndMatch(Winner)
	GameSettings.GameStatus.Value = "Ended"
	Winner = Winner or "NO ONE"
	print("The WINNER IS:", Winner)
	Seconds.Value = 0
	SelectingTime = 15
	workspace.Settings.Rain.Value = false
	workspace.Settings.Sunny.Value = true

	local function ResetPlayer(Player)
		local character = Player.Character
		if not workspace["LDM"].LoadingCharacters:FindFirstChild(Player.Name) then
			local Humanoid = character:FindFirstChild("Humanoid")
			if Humanoid then
				Humanoid.WalkSpeed = 0
				Humanoid.JumpPower = 0
			end

			local Notification = Player:FindFirstChild("PlayerGui") and 
				Player.PlayerGui:FindFirstChild("UI") and 
				Player.PlayerGui.UI:FindFirstChild("Gameplay") and 
				Player.PlayerGui.UI.Gameplay:FindFirstChild("Main") and 
				Player.PlayerGui.UI.Gameplay.Main:FindFirstChild("Notification")
			if Notification then
				Notification.Frame.Object.Text = Winner .. " WON!"
				Notification.Start.Value = true
			end

			task.wait(4)
			Player:LoadCharacter()
		end
	end

	for _, player in ipairs(Players:GetPlayers()) do
		pcall(ResetPlayer, player)
	end
	
	
	GameSettings.GameStatus.Value = "Intermission"
	Decrease.Value = false

	Seconds.Value = IntermissionTime

	task.wait(0.2)
	Decrease.Value = true

	local GameManager = game:GetService("ServerScriptService"):FindFirstChild("GameManager")
	if GameManager then
		GameManager.Enabled = false
		repeat
			task.wait(0.5) 
		until	Seconds.Value == 0
		GameManager.Enabled = true
	end
end

local function SelectDay()
	local TimesOfDay = {
		{Name = "Night", Hour = 3},
		{Name = "Day", Hour = 14},
	}

	local ChosenTime = TimesOfDay[math.random(1, #TimesOfDay)]

	if ChosenTime.Name == "Night" then
		workspace.Settings.Sunny.Value = false
		workspace.Settings.Rain.Value = true
	else
		workspace.Settings.Rain.Value = false
		workspace.Settings.Sunny.Value = true
	end

	game.Lighting.ClockTime = ChosenTime.Hour
end

local function PreparePlayer(player)
	if not player then return end
	task.wait(35)
	pcall(function()
		if not GameSettings.Seekers:FindFirstChild(player.Name) then
			local Spawns = workspace.Map.CurrentMap.Spawns:GetChildren()
			local spawnIndex = math.random(1, #Spawns)
			local selectedSpawn = Spawns[spawnIndex]
			if player.Character and player.Character:FindFirstChild("HumanoidRootPart") then
				player.Character.Parent = GameSettings.Humans
				player.Character.HumanoidRootPart.CFrame = selectedSpawn.CFrame * CFrame.new(0,15,0)
				PlayerUI:Clone().Parent = player.Character.Head	
			end
		end
	end)
end

function Module.StartMatch()
	task.spawn(function()
		ModeSelection()
		SelectRandomMap()
		repeat task.wait(.5) until GameSettings.GameStatus.Value == ""
		SelectDay()
		SelectSeeker()
		repeat task.wait(.5) until GameSettings.GameStatus.Value == "Prepare"
		Seconds.Value = IntermissionTime
		Decrease.Value = true

		local function TrackMatch()
			local SeekerSpawn = MAP:WaitForChild("CurrentMap"):WaitForChild("SeekerSpawn").SpawnLocation
			if Seconds.Value == 0 then
				if GameSettings.GameStatus.Value == "Prepare" then
					Seconds.Value = MatchTime
					for _, SeekerCharacter in GameSettings.Seekers:GetChildren() do
						local SeekerPlayer = Players:GetPlayerFromCharacter(SeekerCharacter)
						if SeekerPlayer then
							LocalRemotes.Visual.Caught:FireClient(SeekerPlayer, "A SEEKER!", Color3.fromRGB(255, 28, 28), "YOU ARE")

							local ToolName = SeekerPlayer.Data.Equipped.Value
							local Tool = ServerStorage.Tools:FindFirstChild("Fists")
							if Tool then
								if Tool:IsA("Tool") then
									Tool:Clone().Parent = SeekerPlayer.Backpack
								elseif Tool:IsA("Frame") then
									Tool:Clone().Parent = SeekerPlayer.PlayerGui.UI.Gameplay["Tools"]
								end
							end
						end

						SeekerCharacter.HumanoidRootPart.CFrame = SeekerSpawn.CFrame * CFrame.new(0, 15, 0)
						EnemyUI:Clone().Parent = SeekerCharacter.Head
						if SeekerAura then
							for _, Particle in SeekerAura:GetChildren() do
								Particle:Clone().Parent = SeekerCharacter.Torso
							end
						end
					end
					task.wait(0.5)
					SeekerSpawn.Transparency = 1
					SeekerSpawn.Information.Enabled = false
					GameSettings.GameStatus.Value = "Active"
					for _, player in Players:GetPlayers() do
						if GameSettings.Humans:FindFirstChild(player.Name) then
							local PlayerGui = player:FindFirstChild("PlayerGui")
							if PlayerGui then
								local Main = PlayerGui:FindFirstChild("UI"):FindFirstChild("Gameplay"):FindFirstChild("Main")
								if Main then
									local Counter = Main:FindFirstChild("Counter")
									local PlayerFrame = Main:FindFirstChild("PlayerFrame")
									if Counter and PlayerFrame then
										Counter.Visible = true
										PlayerFrame.Visible = true
									end
								end
							end
							LocalRemotes.Visual.Caught:FireClient(player, "A HIDER!", Color3.fromRGB(255, 255, 127), "YOU ARE")
						end
					end
				end
			end
		end
		Seconds:GetPropertyChangedSignal("Value"):Connect(TrackMatch)
	end)
end

function Module.SpawnPlayer(player)
	local character = player.Character
	if character and workspace.Characters:FindFirstChild(player.Name) then
		task.spawn(function()
			pcall(function()
				PreparePlayer(player)
			end)
		end)
	end
end

return Module


The selection always selects one seeker even if there's like 7 hiders