--[[
      ESX Property - Properties Made Right!
    Copyright (C) 2025 ESX-Framework

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
]] local GameBuild = GetGameBuildNumber()
Properties = {}
CurrentId = 0
local CurrentDrawing = {}
InProperty = false
PlayerKeys = {}
InCCTV = false
local Blips = {}
local Shell = nil
local PM = Config.PlayerManagement
local CreateThread = CreateThread
local Wait = Wait
local ShowingUIs = {Exit = false, Wardrobe = false, Storage = false, ExitShell = false}
local ox_inventory = exports.ox_inventory
local DoScreenFadeIn = DoScreenFadeIn
local PlayerPedId = PlayerPedId
local GetEntityCoords = GetEntityCoords
local GetEntityHeading = GetEntityHeading
local IsControlJustPressed = IsControlJustPressed
local IsControlPressed = IsControlPressed
local DoScreenFadeOut = DoScreenFadeOut
function RefreshBlips()
  for i = 1, #Blips, 1 do
    RemoveBlip(Blips[i])
    Blips[i] = nil
  end

  for k, v in pairs(Properties) do
    if v.Owned and Config.OwnedBlips then
      if v.Owner == ESX.PlayerData.identifier then
        local Blip = AddBlipForCoord(v.Entrance.x, v.Entrance.y, v.Entrance.z)
        SetBlipSprite(Blip, 40)
        SetBlipAsShortRange(Blip, true)
        SetBlipScale(Blip, 0.8)
        SetBlipColour(Blip, 0)
        BeginTextCommandSetBlipName("STRING")
        AddTextComponentString(v.Name)
        EndTextCommandSetBlipName(Blip)
        SetBlipCategory(Blip, 11)
        Blips[#Blips + 1] = Blip
      elseif PlayerKeys[k] then
        local Blip = AddBlipForCoord(v.Entrance.x, v.Entrance.y, v.Entrance.z)
        SetBlipSprite(Blip, GameBuild >= 2699 and 811 or 134)
        SetBlipAsShortRange(Blip, true)
        SetBlipScale(Blip, 0.9)
        SetBlipColour(Blip, 26)
        BeginTextCommandSetBlipName("STRING")
        AddTextComponentString(v.Name)
        EndTextCommandSetBlipName(Blip)
        SetBlipCategory(Blip, 11)
        Blips[#Blips + 1] = Blip
      end
    elseif not v.Owned and Config.ForSaleBlips then
      local Blip = AddBlipForCoord(v.Entrance.x, v.Entrance.y, v.Entrance.z)
      SetBlipSprite(Blip, 350)
      SetBlipAsShortRange(Blip, true)
      SetBlipScale(Blip, 0.7)
      BeginTextCommandSetBlipName("STRING")
      AddTextComponentString(v.Name)
      EndTextCommandSetBlipName(Blip)
      SetBlipCategory(Blip, 10)
      Blips[#Blips + 1] = Blip
    end
  end

  if PM.Enabled then
    local Blip = AddBlipForCoord(PM.Locations.Entrance)
    SetBlipSprite(Blip, 374)
    SetBlipColour(Blip, 45)
    SetBlipAsShortRange(Blip, true)
    SetBlipScale(Blip, 0.7)
    BeginTextCommandSetBlipName("STRING")
    AddTextComponentString(TranslateCap("office_blip",PM.joblabel))
    EndTextCommandSetBlipName(Blip)
    Blips[#Blips + 1] = Blip
  end
end

RegisterNetEvent("esx_property:syncProperties", function(properties, lastProperty)
  while not ESX.PlayerLoaded and not ESX.PlayerData.identifier do
    Wait(0)
  end
  Properties = properties
  for house, data in pairs(Properties) do
    if data.Keys then
      for ident, vaues in pairs(data.Keys) do
        if vaues and ident == ESX.PlayerData.identifier then
          PlayerKeys[house] = true
        end
      end
    end
  end
  if lastProperty then
    if Properties[lastProperty.id] and (Properties[lastProperty.id].Owner == ESX.PlayerData.identifier or PlayerKeys[lastProperty.id]) then
      AttemptHouseEntry(lastProperty.id)
    else
      ESX.TriggerServerCallback('esx_property:RemoveLastProperty', function()
        SetEntityCoords(ESX.PlayerData.ped, vector3(lastProperty.coords.x, lastProperty.coords.y, lastProperty.coords.z))
      end)
    end
  end
  RefreshBlips()
end)

RegisterNetEvent("esx_property:giveKeyAccess", function(Property)
  ESX.TriggerServerCallback("esx_property:ShouldHaveKey", function(Should)
    if Should then
      PlayerKeys[Property] = true
    end
  end, Property)
end)

RegisterNetEvent("esx_property:RemoveKey", function(Property)
  PlayerKeys[Property] = false
end)

RegisterNetEvent('esx:setJob')
AddEventHandler('esx:setJob', function(job)
  RefreshBlips()
end)

exports("GetProperties", function()
  return Properties
end)

function OpenInteractionMenu(PropertyId, Interaction)
  local Property = Properties[PropertyId]
  if Property.Owned then
    if Interaction == "Wardrobe" then
      Config.WardrobeInteraction(PropertyId, Interaction)
    elseif Interaction == "Storage" then
      if Config.OxInventory then
        exports.ox_inventory:openInventory('stash', {id = 'property-' .. PropertyId, owner = Property.Owner})
      end
    end
  end
end

function GiveKeysMenu(Property)
  ESX.TriggerServerCallback("esx_property:GetInsidePlayers", function(Players)
    local Elements = {{unselectable = true, title = TranslateCap("nearby"), icon = "fas fa-user-plus"},
                      {title = TranslateCap("back"), icon = "fas fa-arrow-left", value = "go_back"}}
    for i = 1, #Players, 1 do
      Elements[#Elements + 1] = {title = Players[i].Name, icon = "far fa-user", index = Players[i].Id, value = "user"}
    end
    ESX.OpenContext("right", Elements, function(menu, element)
      if element.value == "go_back" then
        ManageKeys(Property)
      elseif element.value == "user" then
        ESX.TriggerServerCallback("esx_property:GiveKey", function(KeyGiven)
          if KeyGiven then
            ESX.ShowNotification(TranslateCap("gave_key",element.title), "success")
            ESX.CloseContext()
          else
            ESX.ShowNotification(TranslateCap("key_cannot_give"), "error")
          end
        end, Property, element.index)
      end
    end)
  end, Property)
end

function RemoveKeysMenu(Property)
  ESX.TriggerServerCallback("esx_property:GetPlayersWithKeys", function(Players)
    local Elements = {{unselectable = true, title = TranslateCap("remove_title"), icon = "fas fa-user-plus"},
                      {title = TranslateCap("back"), icon = "fas fa-arrow-left", value = "go_back"}}
    for k, v in pairs(Players) do
      local name = v.name
      local Id = k
      Elements[#Elements + 1] = {title = name, icon = "far fa-user", value = "user", id = Id}
    end
    ESX.OpenContext("right", Elements, function(menu, element)
      if element.value == "go_back" then
        ManageKeys(Property)
      elseif element.value == "user" then
        ESX.TriggerServerCallback("esx_property:RemoveKey", function(KeyGiven)
          if KeyGiven then
            ESX.ShowNotification(TranslateCap("key_revoke_success", element.title), "success")
            ESX.CloseContext()
          else
            ESX.ShowNotification(TranslateCap("key_revoke_error"), "error")
          end
        end, Property, element.id)
      end
    end)
  end, Property)
end

function ManageKeys(Property)
  ESX.HideUI()
  local Elements = {{unselectable = true, title = TranslateCap("key_management"), icon = "fas fa-key"},
                    {title = TranslateCap("back"), icon = "fas fa-arrow-left", value = "go_back"},
                    {title = TranslateCap("give_keys"), icon = "fas fa-plus", value = "give_keys"},
                    {title = TranslateCap("remove_keys"), icon = "fas fa-minus", value = "remove_keys"}}

  ESX.OpenContext("right", Elements, function(menu, element)
    if element.value == "go_back" then
      OpenPropertyMenu(Property)
    end
    if element.value == "give_keys" then
      GiveKeysMenu(Property)
    end
    if element.value == "remove_keys" then
      RemoveKeysMenu(Property)
    end
  end)
end

function SetPropertyName(Property)
  local Name = Properties[Property].setName ~= "" and Properties[Property].setName or Properties[Property].Name
  local Elements = {{unselectable = true, title = TranslateCap("name_edit"), icon = "fa-solid fa-signature"},
                    {icon = "", title = TranslateCap("name"), input = true, inputType = "text", inputValue = Name, inputPlaceholder = Properties[Property].Name,
                     name = "setName"}, {icon = "fa-solid fa-check", title = TranslateCap("confirm"), name = "confirm"}}

  ESX.OpenContext("right", Elements, function(menu, element)
    if element.name == "confirm" then
      ESX.TriggerServerCallback("esx_property:SetPropertyName", function(Set)
        if Set then
          ESX.ShowNotification(TranslateCap("name_edit_success",menu.eles[2].inputValue), "success")
          ESX.CloseContext()
        else
          ESX.ShowNotification(TranslateCap("name_edit_error",menu.eles[2].inputValue), "error")
        end
      end, Property, menu.eles[2].inputValue)
    end
  end)
end

local SettingValue = ""

function PropertyMenuElements(PropertyId)
  local Property = Properties[PropertyId]
  local elements = {{unselectable = true, title = Property.setName ~= "" and Property.setName or Property.Name, icon = "fas fa-home"}}
  if Property.Owned then
    if Property.Locked then
      table.insert(elements, {title = TranslateCap("door_locked"), icon = "fas fa-lock", value = 'property_unlock'})
    else
      table.insert(elements, {title = TranslateCap("door_unlocked"), icon = "fas fa-unlock", value = 'property_lock'})
    end
    if ESX.PlayerData.identifier == Property.Owner then
      table.insert(elements,
        {title = TranslateCap("name_manage"), description = TranslateCap("name_manage_desc"), icon = "fa-solid fa-signature", value = 'property_name'})
    end
    if not InProperty then
      if ESX.PlayerData.identifier == Property.Owner then
        table.insert(elements, {title = TranslateCap("key_management"), description = TranslateCap("key_management_desc"), icon = "fas fa-key", value = 'property_keys'})
        table.insert(elements,
          {title = TranslateCap("sell_title"), description = TranslateCap("sell_desc", ESX.Math.GroupDigits(ESX.Round(Property.Price * 0.6))),
           icon = "fas fa-dollar-sign", value = 'property_sell'})
      end
      if Config.Raiding.Enabled and Property.Locked and ESX.PlayerData.job and ESX.GetPlayerData().job.name == "police" then
        table.insert(elements, {title = TranslateCap("raid_title"), description = TranslateCap("raid_desc"), icon = "fas fa-bomb", value = 'property_raid'})
      end
    else
      if (Config.CCTV.Enabled and Properties[PropertyId].cctv.enabled) and (ESX.PlayerData.identifier == Property.Owner or PlayerKeys[PropertyId]) then
        table.insert(elements, {title = TranslateCap("cctv_title"), description = TranslateCap("cctv_desc"), icon = "fas fa-video", value = 'property_cctv'})
      end
      if (ESX.PlayerData.identifier == Property.Owner or PlayerKeys[PropertyId]) then
        if Config.CanCustomiseInventoryAndWardrobePositions then
          if Config.OxInventory then
            table.insert(elements, {title = TranslateCap("inventory_title"), description = TranslateCap("inventory_desc"),
                                    icon = "fa-solid fa-up-down-left-right", value = 'property_inventory'})
          end
          table.insert(elements, {title = TranslateCap("wardrobe_title"), description = TranslateCap("wardrobe_desc"), icon = "fa-solid fa-up-down-left-right",
                                  value = 'property_wardrobe'})
        end
        table.insert(elements,
          {title = TranslateCap("furniture_title"), description = TranslateCap("furniture_desc"), icon = "fas fa-boxes-stacked", value = 'property_furniture'})
      end
    end
    if (not Property.Locked or Config.OwnerCanAlwaysEnter and ESX.PlayerData.identifier == Property.Owner) and not InProperty then
      table.insert(elements, {title = TranslateCap("enter_title"), icon = "fas fa-door-open", value = 'property_enter'})
    end
    if Property.Locked and not InProperty and
      not (Config.OwnerCanAlwaysEnter and ESX.PlayerData.identifier == Property.Owner or PlayerKeys[PropertyId]) then
      table.insert(elements, {title = TranslateCap("knock_title"), icon = "fa-solid fa-hand-sparkles", value = 'property_knock'})
    end
  else
    if not PM.Enabled then
      table.insert(elements,
        {title = TranslateCap("buy_title"), description = TranslateCap("buy_desc", ESX.Math.GroupDigits(ESX.Round(Property.Price))), icon = "fas fa-shopping-cart",
         value = 'property_buy'})
    else
      if ESX.PlayerData.job.name == PM.job and ESX.PlayerData.job.grade >= PM.Permissions.SellProperty then
        table.insert(elements, {title = TranslateCap("sellplayer_title"), description = TranslateCap("sellplayer_desc", ESX.Math.GroupDigits(ESX.Round(Property.Price))),
                                icon = "fas fa-shopping-cart", value = 'property_sell_re'})
      end
    end
    if not Property.Locked and not InProperty then
      table.insert(elements, {title = TranslateCap("view_title"), icon = "fas fa-door-open", value = 'property_enter'})
    end
  end

  if InProperty and (not Property.Locked or Config.CanAlwaysExit) then
    table.insert(elements, {title = TranslateCap("exit_title"), icon = "fas fa-sign-out-alt", value = 'property_exit'})
  end

  return elements
end

function OpenPropertyMenu(PropertyId)
  if SettingValue ~= "" then
    ESX.ShowNotification(TranslateCap("property_editing_error"))
    return
  end
  ESX.HideUI()
  local Property = Properties[PropertyId]
  local elements = PropertyMenuElements(PropertyId)

  ESX.OpenContext("right", elements, function(menu, element)
    if element.value == "property_unlock" then
      ESX.TriggerServerCallback("esx_property:toggleLock", function(IsUnlocked)
        if IsUnlocked then
          local eles = PropertyMenuElements(PropertyId)
          exports["esx_context"]:Refresh(eles)
        else
          ESX.ShowNotification(TranslateCap("unlock_error"), "error")
        end
      end, PropertyId)
    end
    if element.value == "property_lock" then
      ESX.TriggerServerCallback("esx_property:toggleLock", function(IsUnlocked)
        if IsUnlocked then
          local eles = PropertyMenuElements(PropertyId)
          exports["esx_context"]:Refresh(eles)
        else
          ESX.ShowNotification(TranslateCap("lock_error"), "error")
        end
      end, PropertyId)
    end
    if element.value == "property_cctv" then
      CCTV(PropertyId)
    end
    if element.value == "property_raid" then
      ESX.TriggerServerCallback("esx_property:CanRaid", function(CanRaid)
        if CanRaid then
          ESX.Progressbar(TranslateCap("prep_raid"), 15000, {FreezePlayer = true, animation = Config.Raiding.Animation, onFinish = function()
            ESX.ShowNotification(TranslateCap("raiding"), "success")
            AttemptHouseEntry(PropertyId)
          end, onCancel = function()
            ESX.ShowNotification(TranslateCap("cancel_raiding"), "error")
          end})
        else
          ESX.ShowNotification(TranslateCap("cannot_raid"), "error")
        end
      end, PropertyId)
    end
    if element.value == "property_enter" then
      ESX.CloseContext()
      AttemptHouseEntry(PropertyId)
    end
    if element.value == "property_keys" then
      ESX.CloseContext()
      ManageKeys(PropertyId)
    end
    if element.value == "property_name" then
      ESX.CloseContext()
      SetPropertyName(PropertyId)
    end
    if element.value == "property_furniture" then
      ESX.CloseContext()
      FurnitureMenu(PropertyId)
    end
    if element.value == "property_inventory" then
      ESX.CloseContext()
      ShowingUIs.Exit = false
      SettingValue = "Storage"
      Wait(20)
      ESX.TextUI(TranslateCap("storage_pos_textui"))
      while SettingValue ~= "" do
        Wait(1)
        if IsControlJustPressed(0, 47) then
          SettingValue = ""
          ESX.HideUI()
          ESX.TriggerServerCallback("esx_property:SetInventoryPosition", function(Success)
            if Success then
              ESX.ShowNotification(TranslateCap("storage_pos_success"), "success")
            else
              ESX.ShowNotification(TranslateCap("storage_pos_error"), "error")
            end
          end, PropertyId, GetEntityCoords(ESX.PlayerData.ped))
          break
        end
      end
    end
    if element.value == "property_wardrobe" then
      ESX.CloseContext()
      ShowingUIs.Exit = false
      SettingValue = "Wardrobe"
      Wait(20)
      ESX.TextUI(TranslateCap("wardrobe_pos_textui"))
      while SettingValue ~= "" do
        Wait(1)
        if IsControlJustPressed(0, 47) then
          SettingValue = ""
          ESX.HideUI()
          ESX.TriggerServerCallback("esx_property:SetWardrobePosition", function(Success)
            if Success then
              ESX.ShowNotification(TranslateCap("wardrobe_pos_success"), "success")
            else
              ESX.ShowNotification(TranslateCap("wardrobe_pos_error"), "error")
            end
          end, PropertyId, GetEntityCoords(ESX.PlayerData.ped))
          break
        end
      end
    end
    if element.value == "property_exit" then
      ESX.CloseContext()
      if SettingValue == "" then
        AttemptHouseExit(PropertyId)
      else
        ESX.ShowNotification(TranslateCap("please_finish", SettingValue))
      end
    end
    if element.value == "property_buy" then
      ESX.TriggerServerCallback("esx_property:buyProperty", function(IsBought)
        if IsBought then
          local eles = PropertyMenuElements(PropertyId)
          exports["esx_context"]:Refresh(eles)
        else
          ESX.ShowNotification(TranslateCap("cannot_afford"), "error")
        end
      end, PropertyId)
    end
    if element.value == "property_sell_re" then
      local Elements = {{unselectable = true, title = TranslateCap("select_player")}}
      ESX.TriggerServerCallback("esx_property:GetNearbyPlayers", function(Players)
        if Players then
          for i = 1, #Players do
            Elements[#Elements + 1] = {title = Players[i].name, value = Players[i].source}
          end

          ESX.OpenContext("right", Elements, function(menu, element)
            if element.value then
              ESX.TriggerServerCallback("esx_property:attemptSellToPlayer", function(IsBought)
                if IsBought then
                  local eles = PropertyMenuElements(PropertyId)
                  exports["esx_context"]:Refresh(eles)
                else
                  ESX.ShowNotification(TranslateCap("cannot_sell"), "error")
                end
              end, PropertyId, element.value)
            end
          end)
        end
      end, PropertyId)
    end
    if element.value == "property_knock" then
      ESX.ShowNotification(TranslateCap("knock_on_door"), "success")
      ESX.TriggerServerCallback("esx_property:KnockOnDoor", function(HasKnocked)
        if not HasKnocked then
          ESX.ShowNotification(TranslateCap("nobody_home"), "error")
        end
      end, PropertyId)
    end
    if element.value == "property_sell" then
      ESX.TriggerServerCallback("esx_property:sellProperty", function(IsSold)
        if IsSold then
          local eles = PropertyMenuElements(PropertyId)
          exports["esx_context"]:Refresh(eles)
        else
          ESX.ShowNotification(TranslateCap("cannot_sell"), "error")
        end
      end, PropertyId)
    end
  end, function(menu)
    CurrentDrawing.Showing = false
  end)
end

function AttemptHouseExit(PropertyId)
  local Property = Properties[PropertyId]

  ESX.ShowNotification(TranslateCap("exiting"), "success")
  FreezeEntityPosition(ESX.PlayerData.ped, true)
  InProperty = false
  CurrentId = 0
  SettingValue = ""
  ESX.HideUI()
  ESX.UI.Menu.CloseAll()
  SetRainLevel(-1)
  DoScreenFadeOut(1500)
  Wait(1500)
  TriggerServerEvent("esx_property:leave", PropertyId)
  if Shell then
    DeleteObject(Shell)
    Shell = nil
  end
  if Config.Furniture.Enabled then
    for k, v in pairs(SpawnedFurniture) do
      DeleteObject(v.obj)
    end
    SpawnedFurniture = {}
  end
  Wait(1500)
  FreezeEntityPosition(ESX.PlayerData.ped, false)
  DoScreenFadeIn(1500)
end

RegisterCommand("getoffset", function(source)
  if InProperty then
    local PlayerPed = ESX.PlayerData.ped
    local Pcoords = GetEntityCoords(PlayerPed)
    local Property = Properties[CurrentId]
    local Interior = GetInteriorValues(Property.Interior)
    print(vector3(Property.Entrance.x, Property.Entrance.y, 2000) - Pcoords)
    SendNUIMessage({
      link = tostring(vector3(Property.Entrance.x, Property.Entrance.y, 2000) - Pcoords)
    })
  end
end)

function AttemptHouseEntry(PropertyId)
  local Property = Properties[PropertyId]
  local Interior = GetInteriorValues(Property.Interior)
  if Interior.type == "shell" and not Config.Shells then
    ESX.ShowNotification(TranslateCap("shell_disabled"), "error")
    return
  end
  ESX.ShowNotification(TranslateCap("entering"), "success")
  CurrentId = PropertyId
  ESX.UI.Menu.CloseAll()
  local Property = Properties[CurrentId]
  FreezeEntityPosition(ESX.PlayerData.ped, true)
  DoScreenFadeOut(1500)
  Wait(1500)
  if Interior.type == "shell" then
    ESX.Streaming.RequestModel(joaat(Property.Interior), function()
      if Shell then
        DeleteObject(Shell)
        Shell = nil
      end
      local Pos = vector3(Property.Entrance.x, Property.Entrance.y, 2000)
      Shell = CreateObjectNoOffset(joaat(Property.Interior), Pos + Interior.pos, false, false, false)
      SetEntityHeading(Shell, 0.0)
      while not DoesEntityExist(Shell) do
        Wait(1)
      end
      FreezeEntityPosition(Shell, true)
    end)
  end
  if Properties[PropertyId].furniture then
    for k, v in pairs(Properties[PropertyId].furniture) do
      ESX.Game.SpawnLocalObject(v.Name, v.Pos, function(object)
        SetEntityCoordsNoOffset(object, v.Pos.x, v.Pos.y, v.Pos.z)
        SetEntityHeading(object, v.Heading)
        SetEntityAsMissionEntity(object, true, true)
        FreezeEntityPosition(object, true)
        SpawnedFurniture[k] = {obj = object, data = v}
      end)
    end
  end
  local ShowingTextUI2 = false
  FreezeEntityPosition(ESX.PlayerData.ped, false)
  TriggerServerEvent("esx_property:enter", PropertyId)
  Wait(1500)
  DoScreenFadeIn(1800)
  InProperty = true
  if not Config.OxInventory then
    Interior.positions.Storage = nil
    Properties[CurrentId].positions.Storage = nil
  end

  CreateThread(function()
    while InProperty do
      local Property = Properties[CurrentId]
      local Sleep = 1000
      local Near = false
      SetRainLevel(0.0)
      local PlayerPed = ESX.PlayerData.ped
      local PlayerCoords = GetEntityCoords(PlayerPed)
      if Interior.type == "shell" then
        if #(PlayerCoords - vector3(Property.Entrance.x, Property.Entrance.y, 1999)) < 5.0 then
          Sleep = 0
          DrawMarker(27, vector3(Property.Entrance.x, Property.Entrance.y, 2000.2), 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 50, 50, 200, 200,
            false, false, 2, true, nil, nil, false)
          if #(PlayerCoords.xy - vector2(Property.Entrance.x, Property.Entrance.y)) <= 2.5 then
            Near = true
            if not ShowingUIs.Exit then

              local Pname = Properties[CurrentId].setName ~= "" and Properties[CurrentId].setName or Properties[CurrentId].Name
              ESX.TextUI(TranslateCap("access_textui", Pname))
              ShowingUIs.Exit = true
            end
            if IsControlJustPressed(0, 38) then
              OpenPropertyMenu(CurrentId)
            end
          else
            if not Near and ShowingUIs.Exit and SettingValue == "" then
              ShowingUIs.Exit = false
              ESX.HideUI()
              ESX.CloseContext()
            end
          end
        end

        if Property.Owned then
          for k, v in pairs(Properties[CurrentId].positions) do
            local v = vector3(v.x, v.y, v.z)
            local CanDo = true
            if CanDo then
              local Poss = vector3(Property.Entrance.x, Property.Entrance.y, 1999) - v
              if #(PlayerCoords - Poss) < 5.0 then
                Sleep = 0
                DrawMarker(27, Poss, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 200, 50, 50, 200, false, false, 2, true, nil, nil, false)
                if #(PlayerCoords - Poss) < 2.0 and SettingValue == "" then
                  Near = true
                  if not ShowingUIs[k] then
                    ShowingUIs[k] = true

                    ESX.TextUI(TranslateCap("access_textui", k))
                  end
                  if IsControlJustPressed(0, 38) then
                    OpenInteractionMenu(CurrentId, k)
                  end
                else
                  if not Near and ShowingUIs[k] and SettingValue == "" then
                    ShowingUIs[k] = false
                    ESX.HideUI()
                  end
                end
              end
            end
          end
          if not Near and ShowingUIs and SettingValue == "" then
            ShowingTextUI2 = false
            ESX.HideUI()
          end
        end
      else
        if #(PlayerCoords - Interior.pos) < 5.0 then
          Sleep = 0
          DrawMarker(27, vector3(Interior.pos.xy, Interior.pos.z - 0.98), 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 50, 50, 200, 200, false, false,
            2, true, nil, nil, false)
          if #(PlayerCoords - Interior.pos) < 2.0 then
            if not ShowingUIs.Exit then
              ShowingUIs.Exit = true
              local Pname = Properties[CurrentId].setName ~= "" and Properties[CurrentId].setName or Properties[CurrentId].Name
              ESX.TextUI(TranslateCap("access_textui", Pname))
            end
            if IsControlJustPressed(0, 38) then
              OpenPropertyMenu(CurrentId)
            end
          else
            if ShowingUIs.Exit and SettingValue == "" then
              ShowingUIs.Exit = false
              ESX.HideUI()
              ESX.CloseContext()
            end
          end
        end

        if Property.Owned then
          for k, v in pairs(Properties[CurrentId].positions) do
            v = vector3(v.x, v.y, v.z)
            local CanDo = true

            if CanDo then
              if #(PlayerCoords - v) < 5.0 then
                Sleep = 0
                DrawMarker(27, vector3(v.xy, v.z - 0.98), 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 200, 50, 50, 200, false, false, 2, true, nil,
                  nil, false)
                if #(PlayerCoords - v) < 2.0 then
                  if not ShowingUIs[k] then
                    ShowingUIs[k] = true
                    ESX.TextUI(TranslateCap("access_textui", k))
                  end
                  if IsControlJustPressed(0, 38) then
                    OpenInteractionMenu(CurrentId, k)
                  end
                else
                  if ShowingUIs[k] and SettingValue == "" then
                    ShowingUIs[k] = false
                    ESX.HideUI()
                  end
                end
              end
            end
          end
        end
      end
      Wait(Sleep)
    end
  end)
end

function StoreVehicle(PropertyId)
  local Vehicle = GetVehiclePedIsIn(ESX.PlayerData.ped, false)
  if Vehicle then
    local VehProperties = ESX.Game.GetVehicleProperties(Vehicle)
    VehProperties.DisplayName = GetLabelText(GetDisplayNameFromVehicleModel(VehProperties.model))
    ESX.TriggerServerCallback("esx_property:StoreVehicle", function(result)
      if result then
        SetEntityAsMissionEntity(Vehicle, true, true)
        DeleteVehicle(Vehicle)
        ESX.ShowNotification(TranslateCap("store_success"), "success")
        return
      else
        ESX.ShowNotification(TranslateCap("store_error"), "error")
        return
      end
    end, PropertyId, VehProperties)
  end
end

function AccessGarage(PropertyId)
  ESX.TriggerServerCallback("esx_property:AccessGarage", function(Vehicles)
    if Vehicles then
      local elements = {{unselectable = true, icon = "fas fa-warehouse", title = TranslateCap("property_garage")}}
      for k, v in pairs(Vehicles) do
        elements[#elements + 1] = {title = v.vehicle.DisplayName .. " | " .. v.vehicle.plate, Properties = v.vehicle, index = k}
      end
      ESX.OpenContext("right", elements, function(menu, element)
        if element.Properties then
          ESX.CloseContext()
          ESX.ShowNotification(TranslateCap("retriving_notify",element.Properties.DisplayName))
          if ESX.Game.IsSpawnPointClear(vector3(Properties[PropertyId].garage.pos.x, Properties[PropertyId].garage.pos.y,
            Properties[PropertyId].garage.pos.z), 3.0) then
            ESX.Game.SpawnVehicle(element.Properties.model, Properties[PropertyId].garage.pos, Properties[PropertyId].garage.Heading,
              function(vehicle)
                SetEntityAsMissionEntity(vehicle, true, true)
                ESX.Game.SetVehicleProperties(vehicle, element.Properties)
                TaskWarpPedIntoVehicle(ESX.PlayerData.ped, vehicle, -1)
                SetModelAsNoLongerNeeded(element.Properties.model)
                TriggerServerEvent("esx_property:SetVehicleOut", PropertyId, element.index)
              end)
          end
        end
      end)
    else
      ESX.ShowNotification(TranslateCap("cannot_access"), "error")
      return
    end
  end, PropertyId)
end

CreateThread(function()
  local ShowingTextUI = false
  while true do
    local Sleep = 2000

    if #(Properties) > 0 then
      Sleep = 800
      local nearby = false
      for i = 1, #(Properties) do
        if Properties[i].Entrance then
          local GetEntityCoords = GetEntityCoords
          local IsControlJustPressed = IsControlJustPressed
          local DrawMarker = DrawMarker
          local Coords = GetEntityCoords(ESX.PlayerData.ped)
          local Entrance = vector3(Properties[i].Entrance.x, Properties[i].Entrance.y, Properties[i].Entrance.z)
          if not InCCTV then
            if #(Coords - Entrance) < 10.0 then
              Sleep = 0
              DrawMarker(27, Entrance, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 50, 200, 50, 200, false, false, 2, true, nil, nil, false)
              if #(Coords - Entrance) < 1.5 then
                nearby = true
                local PropertyName = Properties[i].setName ~= "" and Properties[i].setName or Properties[i].Name
                if not CurrentDrawing.Showing or CurrentDrawing.Name ~= PropertyName then
                  CurrentDrawing.Name = PropertyName
                  CurrentDrawing.Showing = true
                  ESX.TextUI(TranslateCap("access_textui", PropertyName))
                end
                if IsControlJustPressed(0, 38) then
                    OpenPropertyMenu(i)
                end
              end
            end
          end
          if Properties[i].garage.enabled and Properties[i].garage.pos and (ESX.PlayerData.identifier == Properties[i].Owner or PlayerKeys[i]) then
            local Garage = vector3(Properties[i].garage.pos.x, Properties[i].garage.pos.y, Properties[i].garage.pos.z)
            if #(Coords - Garage) < 10.0 then
              Sleep = 0
              DrawMarker(36, Garage, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.5, 1.5, 1.5, 50, 200, 50, 200, false, false, 2, true, nil, nil, false)
              if #(Coords - Garage) < 3.0 then
                nearby = true
                if GetVehiclePedIsUsing(ESX.PlayerData.ped) ~= 0 then
                  local veh = GetVehiclePedIsIn(ESX.PlayerData.ped, false)
                  local vehmodel = GetEntityModel(veh)
                  local DisplayName = GetLabelText(GetDisplayNameFromVehicleModel(vehmodel))
                  if not CurrentDrawing.Showing or CurrentDrawing.Name ~= DisplayName then
                    CurrentDrawing.Name = DisplayName
                    CurrentDrawing.Showing = true
                    ESX.TextUI(TranslateCap("store_textui", DisplayName))
                  end
                else
                  if not CurrentDrawing.Showing or CurrentDrawing.Name ~= "Garage" then
                    CurrentDrawing.Name = "Garage"
                    CurrentDrawing.Showing = true
                    ESX.TextUI(TranslateCap("access_textui", "garage"))
                  end
                end
                if IsControlJustPressed(0, 38) then
                  if GetVehiclePedIsUsing(ESX.PlayerData.ped) ~= 0 then
                    StoreVehicle(i)
                  else
                    AccessGarage(i)
                  end
                end
              end
            end
          end
        end
      end
      if not nearby and CurrentDrawing.Showing and SettingValue == "" then
        ESX.HideUI()
        CurrentDrawing.Showing = false
        ESX.CloseContext()
      end
    end
    Wait(Sleep)
  end
end)

function OpenPMQuickMenu(Action)
  if Action == "Entrance" then
    DoScreenFadeOut(1500)
    Wait(1500)
    ESX.TriggerServerCallback("esx_property:PMenterOffice", function(HasEntered)
      if HasEntered then
        ESX.ShowNotification(TranslateCap("enter_office"), "success")
      else
        ESX.ShowNotification(TranslateCap("enter_office_error"), "error")
      end
      Wait(1500)
      DoScreenFadeIn(1500)
    end)
  elseif Action == "Exit" then
    DoScreenFadeOut(1500)
    Wait(1500)
    ESX.TriggerServerCallback("esx_property:PMexitOffice", function(HasExited)
      if HasExited then
        ESX.ShowNotification(TranslateCap("exit_office"), "success")
      else
        ESX.ShowNotification(TranslateCap("exit_office_error"), "error")
      end
      Wait(1500)
      DoScreenFadeIn(1500)
    end)
  elseif Action == "Properties" then
    TriggerEvent("esx_property:AdminMenu")

  elseif Action == "ActionsMenu" then
    local elements = {{unselectable = true, title = TranslateCap("actions"), value = "RealEstateActions"}}

    if ESX.PlayerData.job.name == PM.job then
      if ESX.PlayerData.job.grade >= PM.Permissions.CreateProperty then
        elements[#elements + 1] = {title = TranslateCap("property_create"), value = "CreateProperty"}
      end
      if ESX.PlayerData.job.grade >= PM.Permissions.ManagePropertiesFromQuickActions then
        elements[#elements + 1] = {title = TranslateCap("property_manage"), value = "manage"}
      end
    end
    ESX.OpenContext("right", elements, function(menu, element)
      if element.value == "CreateProperty" then
        TriggerEvent("esx_property:CreateProperty")
      end
      if element.value == "manage" then
        TriggerEvent("esx_property:AdminMenu")
      end
    end)
  end
end

ESX.RegisterInput(TranslateCap("realestate_command"), TranslateCap("realestate_command_desc"), "keyboard", "F5", function()
  ESX.TriggerServerCallback('esx_property:CanAccessRealEstateMenu', function(Access)
    if Access then
      OpenPMQuickMenu("ActionsMenu")
    end
  end)
end)

local PMdrawing = {Entrance = false, Exit = false}
CreateThread(function()
  while PM.Enabled do
    local Sleep = 2500
    local DrawMarker = DrawMarker
    if ESX.IsPlayerLoaded() then
      if ESX.PlayerData.job and ESX.PlayerData.job.name == PM.job then
        Sleep = 1500

        local Coords = GetEntityCoords(ESX.PlayerData.ped)
        local nearby = false

        for k, v in pairs(PM.Locations) do
          local Dist = #(Coords - v)
          if Dist <= 10.0 then
            nearby = true
            Sleep = 0
            DrawMarker(27, v, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 50, 200, 50, 200, false, false, 2, true, nil, nil, false)
            if Dist <= 1.5 then
              if not PMdrawing[k] then
                PMdrawing[k] = true
                ESX.TextUI(TranslateCap("realestate_textui", k))
              end
              if IsControlJustPressed(0, 38) then
                OpenPMQuickMenu(k)
              end
            end
          else
            if not nearby and PMdrawing[k] then
              ESX.HideUI()
              PMdrawing[k] = false
              ESX.CloseContext()
            end
          end
        end
      end
    end
    Wait(Sleep)
  end
end)

local HouseData = {}

RegisterNetEvent("esx_property:CreateProperty", function()
  ESX.TriggerServerCallback('esx_property:CanCreateProperty', function(data)
    if data then
      local GetEntityCoords = GetEntityCoords
      local GetStreetNameAtCoord = GetStreetNameAtCoord
      local GetStreetNameFromHashKey = GetStreetNameFromHashKey
      local Pcoords = GetEntityCoords(ESX.PlayerData.ped)
      local StreetHash = GetStreetNameAtCoord(Pcoords.x, Pcoords.y, Pcoords.z)
      local StreetName = GetStreetNameFromHashKey(StreetHash)
      local Zone = GetZoneAtCoords(Pcoords.x, Pcoords.y, Pcoords.z)
      local ZoneScum = GetZoneScumminess(Zone)
      local SuggestedPrice = Config.ZonePriceOptions.Enabled and Config.ZonePriceOptions.Default * Config.ZonePrices[ZoneScum] or nil
      HouseData = {}
      local Property = {{unselectable = true, icon = "fas fa-plus", title = TranslateCap("menu_title")},
                        {value = 0, title = TranslateCap("element_title1"), icon = "fas fa-list-ol", description = TranslateCap("element_description1"), input = true,
                         inputType = "number", inputPlaceholder = "Number...", inputValue = nil, inputMin = 1, inputMax = 90000, index = "hnumber"},
                        {title = TranslateCap("element_title2"), icon = "fas fa-dollar-sign", input = true, inputType = "number",description = TranslateCap("element_description2"),
                         inputPlaceholder = "Price...", inputValue = SuggestedPrice, inputMin = 1, inputMax = 900000000, index = "price"},
                        {title = TranslateCap("element_title3"), description = TranslateCap("element_description3"), icon = "fas fa-home", index = "interior"},
                        {title = TranslateCap("element_title4"), description = TranslateCap("element_description4"), icon = "fas fa-warehouse", value = {enabled = false},
                         index = "garage", disabled = not (Config.Garage.Enabled)},
                        {title = TranslateCap("element_title5"), description = TranslateCap("element_description5"), icon = "fas fa-video",
                         value = {enabled = false, rot = GetGameplayCamRot(2), maxleft = 80, maxright = -20}, index = "cctv",
                         disabled = not (Config.CCTV.Enabled)},
                        {title = TranslateCap("element_title6"),description = TranslateCap("element_description6"), icon = "fas fa-map-marker-alt", index = "entrance"},
                        {title = TranslateCap("element_create_title"), icon = "fas fa-check", description = TranslateCap("element_create_desc_1"), index = "creation"}}
      local function OpenCreate()
        local opos = {}
        ESX.OpenContext("right", Property, function(menu, element)
          if menu.eles[2] and menu.eles[2].inputValue and menu.eles[1].title == TranslateCap("menu_title") then
            Property[2].inputValue = menu.eles[2].inputValue
            HouseData.name = menu.eles[2].inputValue .. " " .. StreetName
          end
          if menu.eles[3] and menu.eles[3].inputValue and menu.eles[1].title ==  TranslateCap("menu_title") then
            Property[3].inputValue = menu.eles[3].inputValue
            HouseData.price = menu.eles[3].inputValue
          end
          if element.index then
            if element.index == "entrance" then
              local PlayerPos = GetEntityCoords(ESX.PlayerData.ped)
              HouseData.entrance = {x = ESX.Math.Round(PlayerPos.x, 2), y = ESX.Math.Round(PlayerPos.y, 2), z = ESX.Math.Round(PlayerPos.z, 2) - 0.98}
              Property[7].title = TranslateCap("entrance_set_title")
              Property[7].description = TranslateCap("entrance_set_description",HouseData.entrance.x, HouseData.entrance.y, HouseData.entrance.z)
              OpenCreate()
            end
            if element.index == "selectedinterior" then
              HouseData.interior = element.value
              Property[4].title = TranslateCap("interior_set_title")
              Property[4].description = TranslateCap("interior_set_description",element.title)
              OpenCreate()
            end
            if element.index == "IPL" then
              local ints = {{unselectable = true, icon = "fas fa-warehouse", title = TranslateCap("ipl_title")}}
              for i = 1, #(Config.Interiors.IPL) do
                ints[#ints + 1] = {title = Config.Interiors.IPL[i].label, index = "selectedinterior", value = Config.Interiors.IPL[i].value}
                exports["esx_context"]:Refresh(ints, "right")
              end
            end
            if element.index == "Shells" then
              local ints = {{unselectable = true, icon = "fas fa-warehouse", title = TranslateCap("shell_title")}}
              for i = 1, #(Config.Interiors.Shells) do
                ints[#ints + 1] = {title = Config.Interiors.Shells[i].label, index = "selectedinterior", value = Config.Interiors.Shells[i].value}
                exports["esx_context"]:Refresh(ints, "right")
              end
            end
            if element.index == "interior" then
              local catsa = {{unselectable = true, icon = "fas fa-warehouse", title = TranslateCap("types_title")},
                             {title = TranslateCap("ipl_title"), description = TranslateCap("ipl_description"), index = "IPL"}}
              if Config.Shells then
                catsa[3] = {title = TranslateCap("shell_title"), description = TranslateCap("shell_description"), index = "Shells"}
              end
              exports["esx_context"]:Refresh(catsa, "right")
            end
            if element.index == "return" then
              OpenCreate()
            end
            if element.index == "cctv" then
              local status = Property[6].value.enabled and TranslateCap("enabled") or TranslateCap("disabled")
              opos = {{unselectable = true, icon = "fas fa-video", title = TranslateCap("cctv_settings")},
                      {title = TranslateCap("toggle_title"), icon = status == TranslateCap("enabled") and "fas fa-eye" or "fas fa-eye-slash",
                       description = TranslateCap("toggle_description",status), index = "ToggleCCTV"},
                      {title = TranslateCap("cctv_set_title"), icon = "fas fa-rotate", disabled = not Property[6].value.enabled,
                       description = TranslateCap("cctv_set_description"), index = "SetCCTVangle"},
                      {title = TranslateCap("back"), icon = "fas fa-arrow-left", description = TranslateCap("back_description"), index = "return"}}
              exports["esx_context"]:Refresh(opos, "right")
            end
            if element.index == "ToggleCCTV" then
              Property[6].value.enabled = not Property[6].value.enabled
              local status = Property[6].value.enabled and TranslateCap("enabled") or TranslateCap("disabled")
              opos = {{unselectable = true, icon = "fas fa-video", title = TranslateCap("cctv_settings")},
                      {title = TranslateCap("toggle_title"), icon = status == TranslateCap("enabled") and "fas fa-eye" or "fas fa-eye-slash",
                       description = TranslateCap("toggle_description",status), index = "ToggleCCTV"},
                      {title = TranslateCap("cctv_set_title"), icon = "fas fa-rotate", disabled = not Property[6].value.enabled,
                       description = TranslateCap("cctv_set_description"), index = "SetCCTVangle"},
                      {title = TranslateCap("back"), icon = "fas fa-arrow-left", description = TranslateCap("back_description"), index = "return"}}
              exports["esx_context"]:Refresh(opos, "right")
            end
            if Config.Garage.Enabled and element.index == "garage" then
              local status = Property[5].value.enabled and TranslateCap("enabled") or TranslateCap("disabled")
              opos = {{unselectable = true, icon = "fas fa-warehouse", title = TranslateCap("garage_settings")},
                      {title = TranslateCap("toggle_title"), icon = status == TranslateCap("enabled") and "fa-solid fa-toggle-on" or "fa-solid fa-toggle-off",
                       description = TranslateCap("toggle_description",status), index = "ToggleGarage"}}
              if Property[5].value.enabled then
                opos[#opos + 1] = {title = TranslateCap("garage_set_title"), icon = "fas fa-map-marker-alt", disabled = not Property[5].value.enabled,
                                   description = TranslateCap("garage_set_description"), index = "SetGaragePos"}
                if Property[5].value.pos then
                  opos[#opos + 1] = {title = TranslateCap("back"), icon = "fas fa-arrow-left", description = TranslateCap("back_description"), index = "return"}
                end
              else
                opos[#opos + 1] = {title = TranslateCap("back"), icon = "fas fa-arrow-left", description = TranslateCap("back_description"), index = "return"}
              end
              exports["esx_context"]:Refresh(opos, "right")
            end
            if element.index == "ToggleGarage" then
              Property[5].value.enabled = not Property[5].value.enabled
              local status = Property[5].value.enabled and TranslateCap("enabled") or TranslateCap("disabled")
              opos = {{unselectable = true, icon = "fas fa-warehouse", title = TranslateCap("garage_settings")},
                      {title = TranslateCap("toggle_title"), icon = status == TranslateCap("enabled") and "fa-solid fa-toggle-on" or "fa-solid fa-toggle-off",
                       description = TranslateCap("toggle_description",status), index = "ToggleGarage"}}
              if Property[5].value.enabled then
                opos[#opos + 1] = {title = TranslateCap("garage_set_title"), icon = "fas fa-map-marker-alt", disabled = not Property[5].value.enabled,
                                   description = TranslateCap("garage_set_description"), index = "SetGaragePos"}
              else
                opos[#opos + 1] = {title = TranslateCap("back"), icon = "fas fa-arrow-left", description = TranslateCap("back_description"), index = "return"}
              end
              exports["esx_context"]:Refresh(opos, "right")
            end
            if element.index == "SetGaragePos" then
              ESX.CloseContext()
              ESX.TextUI(TranslateCap("garage_textui"))
              while true do
                Wait(0)
                if IsControlJustPressed(0, 38) then
                  local PlayerPos = GetEntityCoords(ESX.PlayerData.ped)
                  Property[5].value.pos = GetEntityCoords(ESX.PlayerData.ped)
                  Property[5].value.heading = GetEntityHeading(ESX.PlayerData.ped)
                  ESX.HideUI()
                  OpenCreate()
                  break
                end
              end
            end
            if element.index == "SetCCTVangle" then
              ESX.CloseContext()
              ESX.TextUI(TranslateCap("cctv_textui_1"))
              local stage = "angle"
              while true do
                Wait(0)
                if IsControlJustPressed(0, 38) then
                  if stage == "angle" then
                    Property[6].value.rot = GetGameplayCamRot(2)
                    ESX.TextUI(TranslateCap("cctv_textui_2"))
                    stage = "maxright"
                  elseif stage == "maxright" then
                    Property[6].value.maxright = GetGameplayCamRot(2).z
                    ESX.TextUI(TranslateCap("cctv_textui_3"))
                    stage = "maxleft"
                  elseif stage == "maxleft" then
                    Property[6].value.maxleft = GetGameplayCamRot(2).z
                    ESX.HideUI()
                    OpenCreate()
                    break
                  end
                end
              end
            end
            if element.index == "creation" then
              if HouseData.price and HouseData.name and HouseData.entrance and HouseData.interior then
                local newProperty = {name = HouseData.name, price = HouseData.price, interior = HouseData.interior, entrance = HouseData.entrance,
                                     cctv = Property[6].value, garage = Property[5].value}
                TriggerServerEvent("esx_property:server:createProperty", newProperty)
                ESX.ShowNotification(TranslateCap("create_success"), "success")
                ESX.CloseContext()
                HouseData = {}
              else
                ESX.ShowNotification(TranslateCap("missing_data"), "error")
              end
            end
          end
        end)
      end
      OpenCreate()
    end
  end)
end)

RegisterNetEvent("esx_property:AdminMenu", function()
  ESX.TriggerServerCallback('esx_property:IsAdmin', function(data)
    if data then

      function ManageProperty(currentProperty)
        local Interior = GetInteriorValues(Properties[currentProperty].Interior)
        ESX.TriggerServerCallback('esx_property:IsAdmin', function(data)
          if data then
            local opos = {}
            local function GetData()
              local elements = {{unselectable = true, icon = "fas fa-cogs", title = "Property Management"},
                                {title = TranslateCap("back"), icon = "fas fa-arrow-left", value = "back"},
                                {title = "Toggle Lock", icon = (Properties[currentProperty].Locked and "fas fa-lock") or "fas fa-unlock",
                                 description = "Lock/Unlock The Property.", value = "lock"},
                                {title = "Enter", description = "Force Entry Into The Property.", icon = "fas fa-door-open", value = "enter"},
                                {title = "Price", icon = "fas fa-dollar-sign", description = "Alter The Price Of The Property.", value = "price"},
                                {title = "Set Interior", description = "Renovate The Property`s Interior.", icon = "fas fa-home", value = "interior"},
                                {title = "Entrance", description = "Set The Entrance As Your Position.", icon = "fas fa-map-marker-alt",
                                 value = "entrance"}}
              if Properties[currentProperty].setName ~= "" then
                elements[#elements + 1] = {title = "Clear Custom Name", icon = "fa-solid fa-ban",
                                           description = "Current Name: " .. Properties[currentProperty].setName, value = "remove_custom_name"}
              end
              if Config.Furniture.Enabled and #(Properties[currentProperty].furniture) > 0 then
                elements[#elements + 1] = {title = "Reset Furniture", description = "Delete All Property Furniture", icon = "fas fa-eraser",
                                           value = "refurni"}
              end
              if Config.Garage.Enabled then
                elements[#elements + 1] = {title = "Garage", description = "Change Garage Settings", icon = "fa-solid fa-warehouse", value = "garage"}
              end
              if Config.CCTV.Enabled then
                elements[#elements + 1] = {title = "CCTV", description = "Change CCTV Settings", icon = "fa-solid fa-camera", value = "cctv"}
              end
              if (Config.OxInventory) and Properties[currentProperty].positions.Storage and
                (ESX.Round(Interior.positions.Storage.x, 2) ~= Properties[currentProperty].positions.Storage.x or
                  ESX.Round(Interior.positions.Storage.y, 2) ~= Properties[currentProperty].positions.Storage.y) then
                elements[#elements + 1] = {title = "Reset Storage Position", description = "Set Storage Position To Interior Default.",
                                           icon = "fas fa-eraser", value = "restorage"}
              end
              if Interior.positions.Wardrobe then
                if ESX.Round(Interior.positions.Wardrobe.x, 2) ~= ESX.Round(Properties[currentProperty].positions.Wardrobe.x, 2) or
                  ESX.Round(Interior.positions.Wardrobe.y, 2) ~= ESX.Round(Properties[currentProperty].positions.Wardrobe.y, 2) then
                  elements[#elements + 1] = {title = "Reset Wardrobe Position", description = "Set Wardrobe Position To Interior Default.",
                                             icon = "fas fa-eraser", value = "rewardrobe"}
                end
              end
              if Properties[currentProperty].Owned then
                elements[#elements + 1] = {title = "Remove Owner", icon = "fas fa-user-times", description = "Evict The Owner Of The Property.",
                                           value = "removeowner"}
              end
              return elements
            end
            ESX.OpenContext("right", GetData(), function(menu, element)
              if element.value then
                if element.value == "lock" then
                  ESX.TriggerServerCallback("esx_property:toggleLock", function(IsUnlocked)
                    if IsUnlocked then
                      ESX.ShowNotification("Lock Toggled!", "success")
                      exports["esx_context"]:Refresh(GetData())
                    else
                      ESX.ShowNotification("You Cannot Lock This Property", "error")
                    end
                  end, currentProperty)
                end
                if element.value == "enter" then
                  AttemptHouseEntry(currentProperty)
                end
                if element.value == "removeowner" then
                  ESX.TriggerServerCallback("esx_property:evictOwner", function(Evicted)
                    if Evicted then
                      ESX.ShowNotification("Owner Evicted!", "success")
                      exports["esx_context"]:Refresh(GetData())
                    else
                      ESX.ShowNotification("You Cannot Evict This Owner!", "error")
                    end
                  end, currentProperty)
                end
                if element.value == "garage" then
                  local status = Properties[currentProperty].garage.enabled and TranslateCap("enabled") or TranslateCap("disabled")
                  opos = {{unselectable = true, icon = "fas fa-warehouse", title = TranslateCap("garage_settings")},
                          {title = "Toggle Usage", icon = status == TranslateCap("enabled") and "fa-solid fa-toggle-on" or "fa-solid fa-toggle-off",
                           description = "Current Status: " .. status, value = "ToggleGarage"}}
                  if Properties[currentProperty].garage.enabled then
                    opos[#opos + 1] = {title = "Set Position", icon = "fas fa-map-marker-alt",
                                       disabled = not Properties[currentProperty].garage.enabled,
                                       description = "Sets the Garage Position to your Players Position", value = "SetGaragePos"}
                    if Properties[currentProperty].garage.pos then
                      opos[#opos + 1] = {title = TranslateCap("back"), icon = "fas fa-arrow-left", description = "return to Property Management.",
                                         value = "return"}
                    end
                  else
                    opos[#opos + 1] = {title = TranslateCap("back"), icon = "fas fa-arrow-left", description = "return to Property Management", value = "return"}
                  end
                  exports["esx_context"]:Refresh(opos, "right")
                end
                if element.value == "cctv" then
                  local status = Properties[currentProperty].cctv.enabled and TranslateCap("enabled") or TranslateCap("disabled")
                  opos = {{unselectable = true, icon = "fas fa-warehouse", title = TranslateCap("cctv_settings")},
                          {title = "Toggle Usage", icon = status == TranslateCap("enabled") and "fa-solid fa-toggle-on" or "fa-solid fa-toggle-off",
                           description = "Current Status: " .. status, value = "ToggleCCTV"}}
                  if Properties[currentProperty].cctv.enabled then
                    opos[#opos + 1] = {title = "Set Angle", icon = "fas fa-map-marker-alt", disabled = not Properties[currentProperty].cctv.enabled,
                                       description = "Sets the Angle of the Camera.", value = "SetCCTVangle"}
                    if Properties[currentProperty].cctv.rot then
                      opos[#opos + 1] = {title = TranslateCap("back"), icon = "fas fa-arrow-left", description = "return to Property Management.",
                                         value = "return"}
                    end
                  else
                    opos[#opos + 1] = {title = TranslateCap("back"), icon = "fas fa-arrow-left", description = "return to Property Management", value = "return"}
                  end
                  exports["esx_context"]:Refresh(opos, "right")
                end
                if element.value == "ToggleGarage" then
                  ESX.TriggerServerCallback("esx_property:toggleGarage", function(IsUnlocked, enabled)
                    if IsUnlocked then
                      ESX.ShowNotification("Garage Toggled!", "success")
                      local status = enabled and TranslateCap("enabled") or TranslateCap("disabled")
                      opos = {{unselectable = true, icon = "fas fa-warehouse", title = TranslateCap("garage_settings")},
                              {title = "Toggle Usage", icon = status == TranslateCap("enabled") and "fa-solid fa-toggle-on" or "fa-solid fa-toggle-off",
                               description = "Current Status: " .. status, value = "ToggleGarage"}}
                      if enabled then
                        opos[#opos + 1] = {title = "Set Position", icon = "fas fa-map-marker-alt", disabled = not enabled,
                                           description = "Sets the Garage Position to your Players Position", value = "SetGaragePos"}
                        if Properties[currentProperty].garage.pos then
                          opos[#opos + 1] = {title = TranslateCap("back"), icon = "fas fa-arrow-left", description = "return to Property Management.",
                                             value = "return"}
                        end
                      else
                        opos[#opos + 1] = {title = TranslateCap("back"), icon = "fas fa-arrow-left", description = "return to Property Management",
                                           value = "return"}
                      end
                      exports["esx_context"]:Refresh(opos, "right")
                    else
                      ESX.ShowNotification("You ~r~Cannot~s~ Toggle This Option!", "error")
                    end
                  end, currentProperty)
                end
                if element.value == "ToggleCCTV" then
                  ESX.TriggerServerCallback("esx_property:toggleCCTV", function(IsUnlocked, enabled)
                    if IsUnlocked then
                      ESX.ShowNotification("CCTV Toggled!", "success")
                      local status = enabled and TranslateCap("enabled") or TranslateCap("disabled")
                      opos = {{unselectable = true, icon = "fas fa-warehouse", title = TranslateCap("cctv_settings")},
                              {title = "Toggle Usage", icon = status == TranslateCap("enabled") and "fa-solid fa-toggle-on" or "fa-solid fa-toggle-off",
                               description = "Current Status: " .. status, value = "ToggleCCTV"}}
                      if enabled then
                        opos[#opos + 1] = {title = "Set Angle", icon = "fas fa-map-marker-alt", disabled = not enabled,
                                           description = "Sets the Angle of the Camera.", value = "SetCCTVangle"}
                        if Properties[currentProperty].cctv.rot then
                          opos[#opos + 1] = {title = TranslateCap("back"), icon = "fas fa-arrow-left", description = "return to Property Management.",
                                             value = "return"}
                        end
                      else
                        opos[#opos + 1] = {title = TranslateCap("back"), icon = "fas fa-arrow-left", description = "return to Property Management",
                                           value = "return"}
                      end
                      exports["esx_context"]:Refresh(opos, "right")
                    else
                      ESX.ShowNotification("You ~r~Cannot~s~ Toggle This Option!", "error")
                    end
                  end, currentProperty)
                end
                if element.value == "SetGaragePos" then
                  ESX.CloseContext()
                  ESX.TextUI("Press ~b~[E]~s~ to Set Position")
                  SettingValue = "Garage"
                  while SettingValue ~= "" do
                    Wait(0)
                    if IsControlJustPressed(0, 38) then
                      ESX.TriggerServerCallback("esx_property:SetGaragePos", function(IsChanged)
                        if IsChanged then
                          ESX.HideUI()
                          SettingValue = ""
                          ESX.ShowNotification("Position Changed!", "success")
                          ManageProperty(currentProperty)
                        else
                          ESX.ShowNotification("You ~r~Cannot~s~ Change This Option!", "error")
                        end
                      end, currentProperty, GetEntityHeading(ESX.PlayerData.ped))
                      break
                    end
                  end
                end
                if element.value == "SetCCTVangle" then
                  ESX.CloseContext()
                  ESX.TextUI("Press ~b~[E]~s~ to Set Angle")
                  local stage = "angle"
                  SettingValue = "cctv"
                  local Angles = {}
                  while stage do
                    Wait(0)
                    if IsControlJustPressed(0, 38) then
                      if stage == "angle" then
                        Angles.rot = GetGameplayCamRot(2)
                        ESX.TextUI("Press ~b~[E]~s~ to Set Max Right Roation")
                        stage = "maxright"
                      elseif stage == "maxright" then
                        Angles.maxright = GetGameplayCamRot(2).z
                        ESX.TextUI("Press ~b~[E]~s~ to Set Max Left Roation")
                        stage = "maxleft"
                      elseif stage == "maxleft" then
                        Angles.maxleft = GetGameplayCamRot(2).z
                        ESX.TriggerServerCallback("esx_property:SetCCTVangle", function(IsChanged)
                          if IsChanged then
                            SettingValue = ""
                            stage = nil
                            ESX.HideUI()
                            ESX.ShowNotification("Angle Changed!", "success")
                            ManageProperty(currentProperty)
                          else
                            ESX.ShowNotification("You ~r~Cannot~s~ Change This Option!", "error")
                          end
                        end, currentProperty, Angles)
                        break
                      end
                    end
                  end
                end
                if element.value == "remove_custom_name" then
                  ESX.TriggerServerCallback("esx_property:RemoveCustomName", function(Cleared)
                    if Cleared then
                      ESX.ShowNotification("Property Name Reset!", "success")
                      exports["esx_context"]:Refresh(GetData())
                    else
                      ESX.ShowNotification("You Cannot Reset This Property`s Name!", "error")
                    end
                  end, currentProperty)
                end
                if element.value == "refurni" then
                  ESX.TriggerServerCallback("esx_property:RemoveAllfurniture", function(Removed)
                    if Removed then
                      ESX.ShowNotification("Furniture Reset!", "success")
                      exports["esx_context"]:Refresh(GetData())
                    else
                      ESX.ShowNotification("You Cannot Reset This Property!", "error")
                    end
                  end, currentProperty)
                end
                if element.value == "restorage" then
                  ESX.TriggerServerCallback("esx_property:SetInventoryPosition", function(Reset)
                    if Reset then
                      ESX.ShowNotification("~b~Storage~s~ Position Reset!", "success")
                      exports["esx_context"]:Refresh(GetData())
                    else
                      ESX.ShowNotification("You Cannot Reset This Property!", "error")
                    end
                  end, currentProperty, Interior.positions.Storage, true)
                end
                if element.value == "rewardrobe" then
                  ESX.TriggerServerCallback("esx_property:SetWardrobePosition", function(Reset)
                    if Reset then
                      ESX.ShowNotification("~b~Wardrobe~s~ Position Reset!", "success")
                      exports["esx_context"]:Refresh(GetData())
                    else
                      ESX.ShowNotification("You Cannot Reset This Property!", "error")
                    end
                  end, currentProperty, Interior.positions.Wardrobe, true)
                end
                if element.value == "back" then
                  AdminOptions(currentProperty)
                end
                if element.value == "return" then
                  exports["esx_context"]:Refresh(GetData())
                end
                if element.value == "price" then
                  ESX.UI.Menu.Open('dialog', GetCurrentResourceName(), 'PropertyPrice', {title = "Property Price"}, function(data4, menu4)
                    if data4.value then
                      ESX.TriggerServerCallback("esx_property:ChangePrice", function(IsChanged)
                        if IsChanged then
                          ESX.ShowNotification("Price Changed!", "success")
                          menu4.close()
                        else
                          ESX.ShowNotification("You Cannot Change this property!", "error")
                        end
                      end, currentProperty, tonumber(data4.value))
                    end
                  end, function(data4, menu4)
                    menu4.close()
                  end)
                end
                if element.value == "interior" then
                  local elements = {{unselectable = true, icon = "fas fa-warehouse", title = "Interior Types"},
                                    {title = "IPL Interiors", description = "Native GTA Interiors, Made by R*", value = "IPL"}}
                  if Config.Shells then
                    elements[3] = {title = "Custom Interiors", description = "Custom Interiors, Made by You", value = "Shells"}
                  end
                  ESX.OpenContext("right", elements, function(menu, element)
                    if element.value then
                      local elements = {{unselectable = true, icon = "fas fa-warehouse", title = "Interiors"}}
                      for i = 1, #(Config.Interiors[element.value]) do
                        elements[#elements + 1] = {title = Config.Interiors[element.value][i].label, value = Config.Interiors[element.value][i].value}
                      end
                      ESX.OpenContext("right", elements, function(menu, element)
                        if element.value then
                          ESX.TriggerServerCallback("esx_property:ChangeInterior", function(IsChanged)
                            if IsChanged then
                              ESX.ShowNotification("Interior Changed!", "success")
                              ESX.CloseContext()
                            else
                              ESX.ShowNotification("You Cannot Change this property!", "error")
                            end
                          end, currentProperty, element.value)
                        end
                      end)
                    end
                  end, function()
                    ManageProperty(currentProperty)
                  end)
                end
                if element.value == "entrance" then
                  ESX.TriggerServerCallback("esx_property:ChangeEntrance", function(IsChanged)
                    if IsChanged then
                      ESX.ShowNotification("Entrance Changed!", "success")
                    else
                      ESX.ShowNotification("You Cannot Change this property!", "error")
                    end
                  end, currentProperty, GetEntityCoords(ESX.PlayerData.ped))
                end
              end
            end)
          end
        end)
      end

      function AdminOptions(currentProperty)
        ESX.TriggerServerCallback('esx_property:IsAdmin', function(data)
          if data then
            local elements = {{unselectable = true, icon = "fas fa-home", title = "Property Options"},
                              {title = TranslateCap("back"), icon = "fas fa-arrow-left", value = "back"},
                              {title = "Manage", icon = "fas fa-cogs", description = "Alter This Property's Settings.", value = "manage"},
                              {title = "Teleport", description = "Teleport To This Property.", icon = "fas fa-map-marker-alt", value = "goto"},
                              {title = "Set GPS", description = "Set GPS position To Property.", icon = "fa-solid fa-location-dot", value = "gps"},
                              {title = "Delete", icon = "fas fa-trash-alt", description = "Remove Current Property.", value = "delete"}}

            ESX.OpenContext("right", elements, function(menu, element)
              if element.value then
                if element.value == "goto" then
                  SetEntityCoords(ESX.PlayerData.ped, Properties[currentProperty].Entrance.x, Properties[currentProperty].Entrance.y,
                    Properties[currentProperty].Entrance.z)
                  ESX.ShowNotification("Teleported to Property!")
                end
                if element.value == "gps" then
                  SetNewWaypoint(Properties[currentProperty].Entrance.x, Properties[currentProperty].Entrance.y)
                  ESX.ShowNotification("GPS Set!")
                end
                if element.value == "back" then
                  AdminMenu()
                end
                if element.value == "delete" then
                  ESX.TriggerServerCallback("esx_property:deleteProperty", function(response)
                    if response then
                      ESX.ShowNotification("Property Deleted!", "success")
                      ESX.CloseContext()
                    else
                      ESX.ShowNotification("You Cannot Delete This Property", "error")
                    end
                  end, currentProperty)
                end

                if element.value == "manage" then
                  ManageProperty(currentProperty)
                end
              end
            end)
          end
        end)
      end

      function AdminMenu()
        ESX.TriggerServerCallback('esx_property:IsAdmin', function(data)
          if data then
            local elements = {{unselectable = true, icon = "fas fa-home", title = "Properties Management"}}
            for i = 1, #(Properties) do
              if Properties[i].Entrance then
                local description = ""
                if Properties[i].setName ~= "" then
                  description = description .. "\nName: " .. Properties[i].setName
                end
                if Properties[i].Owned then
                  description = description .. "\nOwner: " .. Properties[i].OwnerName
                end
                table.insert(elements, {title = Properties[i].Name, value = i, description = description, icon = "fas fa-home"})
              end
            end
            ESX.OpenContext("right", elements, function(menu, element)
              if element.value then
                ESX.CloseContext()
                AdminOptions(element.value)
              end
            end)
          end
        end)
      end

      AdminMenu()
    else
      ESX.ShowNotification("You ~r~Cannot~s~ Access This Menu!", 5000, "error")
    end
  end)
end)

