require("lib/enums")

function RevealAll()
  for _, actor in pairs(GetAllActors()) do
    Reveal(actor)
  end
end

function RevealNPCsInSector(locationName)
  local location = GetLocation(locationName)
  local numberOfActors = GetNumberOfActorsInSector(location)
  for i = 0, numberOfActors - 1 do
    local actor = GetActorInSector(location, i)
    if IsActorNPC(actor) then
      Reveal(actor)
    end
  end
end

function RevealActors(actors)
  for _, actor in pairs(actors) do
    if IsActorNPC(actor) then
      Reveal(actor)
    end
  end
end

function GetAllActorsInZone(zonePointer)
  local actors = {}
  local actorCount = GetNumberOfActorsInSector(zonePointer)

  for i = 1, actorCount do
    local actor = GetActorInSector(zonePointer, i - 1)
    if IsActorNPC(actor) then
      table.insert(actors, actor)
    end
  end

  return actors
end

function HandleScrollCameraSequence(actorSource, targetLocation)
  StartSequence()
  SequenceSetZoomLevel(ZoomLevel.default)
  Then()
  SequenceLockUser()
  SequenceFreezeAll(true)
  Then()
  SequenceScrollCameraTo(GetLocation(targetLocation))
  Then()
  SequenceTimer(55)
  Then()
  SequenceJumpCameraTo(GetActorLocation(actorSource))
  Then()
  SequenceUnLockUser()
  SequenceFreezeAll(false)
  EndSequence()
end

function RemoveScrollFromNPC(npc)
  if IsActorNPC(npc) then
    AttachScrollToNPC(npc, 0) -- Aka remove scroll from this npc
  end
end

function UpdateScrollState(scroll, state)
  if GetScrollState(scroll) < state then
    SetScrollState(scroll, state)
  end
end

function ActivateActors(actors)
  for _, actor in pairs(actors) do
    Activate(actor)
    UnlockAI(actor)
  end
end

function DeactivateActors(actors)
  for _, actor in pairs(actors) do
    Deactivate(actor)
    LockAI(actor, false)
  end
end

---@param actor pointer The actor to set active of.
---@param value boolean The value of active to set.
function ActivateNPC(actor, value)
  if(value == false) then
    LockAI(actor, false)
    Deactivate(actor)
  else
    UnlockAI(actor)
    Activate(actor)
  end
end

---needs a list / table of items e. g. {GetItem("Arrows_2"), GetItem("Money_3"), etc.}
function ActivateItems(items)
  for _, item in pairs(items) do
    Activate(item)
  end
end

---needs a list / table of items e. g. {GetItem("Arrows_2"), GetItem("Money_3"), etc.}
function DeactivateItems(items)
  for _, item in pairs(items) do
    Deactivate(item)
  end
end

---needs a list / table of scrolls e. g. {GetScroll("Scroll_10"), GetScroll("Scroll_11"), etc.}
function DeactivateScrolls(scrolls)
  for _, scroll in pairs(scrolls) do
    SetScrollState(scroll, ScrollState.hidden)
  end
end

---needs a list / table of scrolls e. g. {GetScroll("Scroll_10"), GetScroll("Scroll_11"), etc.}
function ActivateScrolls(scrolls)
  for _, scroll in pairs(scrolls) do
    SetScrollState(scroll, ScrollState.default)
  end
end

function SetCurrentActorPost(actor)
  AssignPost(actor, GetActorLocation(actor), GetActorDirection(actor))
end

---needs a list / table of indexes e. g. {1, 2, 3}
function ActivateDoors(doors)
  for _, door in pairs(doors) do
    ActivateDoorMouseSector(true, GetDoorScript(door))
  end
end

---needs a list / table of indexes e. g. {1, 2, 3}
function DeactivateDoors(doors)
  for _, door in pairs(doors) do
    ActivateDoorMouseSector(false, GetDoorScript(door))
  end
end

---needs a list / table of indexes e. g. {1, 2, 3}
function ActivateAnimations(animations)
  for _, animation in pairs(animations) do
    Activate(GetActorScript(animation))
  end
end

---needs a list / table of indexes e. g. {1, 2, 3}
function DeactivateAnimations(animations)
  for _, animation in pairs(animations) do
    Deactivate(GetActorScript(animation))
  end
end

function ActivateSherwoodSigns()
  for name, actor in pairs(GetAllActors()) do
    if name:find("Panneau_") then
      Activate(actor)
    end
  end
end

function DeactivateSherwoodSigns()
  for name, actor in pairs(GetAllActors()) do
    if name:find("Panneau_") then
      Deactivate(actor)
    end
  end
end

function PrintAll()
  for i = 0, GetNumberOfActorsInEngine() do
    print(i, ":", GetActorName(GetActorScript(i)))
  end
end

function IsPCSafe(actor, exitLocations)
  for _, location in pairs(exitLocations) do
    if IsInside(actor, GetLocation(location)) then
      return true
    end
  end
  return false
end

LockAllAI = function()
  for _, actor in pairs(GetAllActors()) do
    if IsActorNPC(actor) then
      LockAI(actor, true)
    end
  end
end

UnlockAllAI = function()
  for _, actor in pairs(GetAllActors()) do
    if IsActorNPC(actor) then
      UnlockAI(actor)
    end
  end
end

---Unlocks AI of all NPCs whose custom value of UnlockableAI is not 1.
function UnlockUnlockableAI()
  for i = 0, (GetNumberOfActorsInEngine() - 1) do
    local actor = GetActorScript(i)
    if IsActorNPC(actor) then
      if not (GetCustomNPCValue(actor, NPCValueIndices.UnlockableAI) == 1) then
        UnlockAI(actor)
      end
    end
  end
end

---Deactivate, LockAI and set their custom value of UnlockableAI to 1.
---@param actor pointer A pointer to the character.
function DeactivateInside(actor)
  DeactivateInsideCustom(actor, false)
end
---Deactivate, LockAI and set their custom value of UnlockableAI to 1.
---@param actor pointer A pointer to the character.
---@param aiRememberEvents boolean
function DeactivateInsideCustom(actor, aiRememberEvents)
  Deactivate(actor)
  LockOnPlaceCustom(actor, aiRememberEvents)
end

---LockAI and set their custom value of UnlockableAI to 1.
---@param actor pointer A pointer to the character.
function LockOnPlace(actor)
  LockOnPlaceCustom(actor, false)
end

---LockAI and set their custom value of UnlockableAI to 1.
---@param actor pointer A pointer to the character.
---@param aiRememberEvents boolean
function LockOnPlaceCustom(actor, aiRememberEvents)
  LockAI(actor, aiRememberEvents)
  SetCustomNPCValue(actor, NPCValueIndices.UnlockableAI, 1)
end

---Activate, UnlockAI and set their custom value of UnlockableAI to 0.
---@param actor pointer The person inside.
function ShowPersonInside(actor)
  Activate(actor)
  UnlockAI(actor)
  SetCustomNPCValue(actor, NPCValueIndices.UnlockableAI, 0)
end

---comment Locks a door on a given index for heroes, civilians and villains.
---@param index integer The index of the door to lock.
function LockDoorForAll(index)
  local door = GetDoorScript(index)
  SetDoorLockedPC(door, true)
  SetDoorLockedNPCVillain(door, true)
  SetDoorLockedNPCCivilian(door, true)
end

---comment Locks a door on a given index for heroes, but make it unlockable.
---@param index integer The index of the door to lock.
function DoorLockedButUnlockable(index)
  local door = GetDoorScript(index)
  SetDoorLockedPC(door, true)
  SetDoorUnlockable(door, true)
end

---comment Add all items from array "other" to array "into".
---@param into [any] The array to copy into.
---@param other [any] The array to copy from.
---@return [any] Result The resulting into array.
function ConcatInPlace(into, other)
  for _, value in pairs(other) do
    table.insert(into, value)
  end
  return into
end

---comment Add all items from both input arrays into a new one.
---@param first [any]
---@param second [any]
---@return [any] array
function ConcatInNew(first, second)
  return ConcatInPlace(ConcatInPlace({}, first), second)
end

---Experimental stuff
-- local actionId = 0
-- local lastKeyPressTime = 0
-- local debounceDelay = 0.2

-- function KeyPressed(key)
--   local currentTime = os.clock()

--   if currentTime - lastKeyPressTime < debounceDelay then
--     return
--   end

--   lastKeyPressTime = currentTime

--   if key == 21 then -- Y
--     actionId = actionId - 1
--     print("Dec  : " .. tostring(actionId))
--   elseif key == 22 then -- U
--     StartSequence()
--     SequenceAction(GetActor("Lancier_Bleu_19"), actionId, 70)
--     EndSequence()
--     print("Play : " .. tostring(actionId))
--   elseif key == 23 then -- I
--     actionId = actionId + 1
--     print("Inc  : " .. tostring(actionId))
--   end
-- end
