-- The Unbreakable Vehicles Script by Chaplain Grimaldus --
local WriteInfoLogs = true -- Set to true to enable info logging

local Re = re
local Sdk = sdk
local Log = log
local Json = json

local status, Hotkeys = pcall(require, "Hotkeys/Hotkeys")
local HotkeysAvailable = status

-- Log Functions
local function log_info(info_message)
  if WriteInfoLogs then
    Log.info("[Chaplain Grimaldus > Invincible Vehicles]: " .. info_message)
  end
end

local function log_error(error_message)
  Log.error("[Chaplain Grimaldus > Invincible Vehicles]: " .. error_message)
end

log_info("Loaded")

-- Default Config with default hotkeys
local Config = {
  Hotkeys = {
    ["Set Vehicles Invincible"] = "I", -- Default hotkey for making vehicles invincible
    ["Set Vehicles Vulnerable"] = "U", -- Default hotkey for making vehicles vulnerable
  }
}

-- Load configuration from JSON on script start
local ConfigFilePath = "ChaplainGrimaldus\\InvincibleVehiclesConfig.json"

local function save_config()
  local success, err = pcall(Json.dump_file, ConfigFilePath, Config)
  if not success then
    log_error("Error saving configuration: " .. tostring(err))
  else
    log_info("Configuration saved successfully.")
  end
end

local function load_config()
  local status, data = pcall(Json.load_file, ConfigFilePath)
  if status and type(data) == "table" and data.Hotkeys then
    Config.Hotkeys = data.Hotkeys
    log_info("Configuration loaded successfully.")
  else
    log_info("Using default hotkeys, config file not found or corrupted.")
  end
end

-- Apply the loaded hotkeys or default ones
if HotkeysAvailable then
  load_config()
  Hotkeys.setup_hotkeys(Config.Hotkeys)
  log_info("Hotkeys setup complete")
else
  log_error("Hotkeys utility not available")
end

-- Vehicle list
local vehicleMapping = {
  "Vehicle_om009b_Bike",
  "PREF_Vehicle_om009a_Hammer_Em4d",
  "Vehicle_om0009_2DoorCar",
}

local currentScene = nil
local playerFound = false
local delayCounter = 0
local delayThreshold = 60 -- Number of frames to wait before retrying (adjust as needed)

-- Function to set vehicles' invincibility status
local function set_vehicles_invincible(scene, invincible)
  if not scene then
    log_error("No valid scene found to set vehicle invincibility")
    return
  end

  for _, vehicle_name in ipairs(vehicleMapping) do
    local vehicle = scene:call("findGameObject(System.String)", vehicle_name)
    if vehicle then
      local hitPointController = vehicle:call("getComponent(System.Type)", sdk.typeof("app.solid.HitPointController"))
      if hitPointController then
        hitPointController:set_Invincible(invincible)
        hitPointController:set_NoDamage(invincible)
        log_info(vehicle_name .. (invincible and " set to invincible" or " set to vulnerable"))
      else
        log_info(vehicle_name .. " HitPointController not found")
      end
    else
      log_info(vehicle_name .. " not found!")
    end
  end
end

-- Scene updating logic with delay mechanism
Re.on_pre_application_entry("LockScene", function()
  local sceneManager = Sdk.get_native_singleton("via.SceneManager")
  if not sceneManager then
    log_info("SceneManager not found")
    return
  end

  local scene = Sdk.call_native_func(sceneManager, Sdk.find_type_definition("via.SceneManager"), "get_CurrentScene")
  if scene ~= currentScene then
    playerFound = false
    currentScene = scene
    delayCounter = 0 -- Reset the delay counter when the scene changes
    log_info("Scene has changed, resetting invincibility")
  end

  -- Keep checking for player in the scene with delay
  if scene and not playerFound and delayCounter >= delayThreshold then
    local player = scene:call("findGameObject(System.String)", "Pl_Frank")
    if player then
      playerFound = true
      log_info("Player found in scene")
      -- Once the player is found, set all vehicles invincible
      set_vehicles_invincible(scene, true)
    else
      log_info("Player not yet found, retrying...")
    end
  end
end)

-- Frame update function to handle delay counter and hotkeys
Re.on_frame(function()
  if not playerFound then
    delayCounter = delayCounter + 1 -- Increment the counter each frame until the threshold is reached
  end

  if HotkeysAvailable then
    -- Check if "Set Vehicles Invincible" hotkey is pressed
    if Hotkeys.check_hotkey("Set Vehicles Invincible", false, true) then
      if currentScene then
        set_vehicles_invincible(currentScene, true)
      else
        log_error("No current scene available, cannot set vehicles to invincible")
      end
    end

    -- Check if "Set Vehicles Vulnerable" hotkey is pressed
    if Hotkeys.check_hotkey("Set Vehicles Vulnerable", false, true) then
      if currentScene then
        set_vehicles_invincible(currentScene, false)
      else
        log_error("No current scene available, cannot set vehicles to vulnerable")
      end
    end
  end
end)

-- UI to allow users to set their own hotkeys
Re.on_draw_ui(function()
  if imgui.tree_node("Invincible Vehicles Config") then
    local configChanged = false

    -- Hotkey setter for setting vehicles invincible
    imgui.text("Set Vehicles Invincible Hotkey:")
    if HotkeysAvailable then
      local invincibleHotkeyChanged = Hotkeys.hotkey_setter("Set Vehicles Invincible")
      if invincibleHotkeyChanged then
        Config.Hotkeys["Set Vehicles Invincible"] = Hotkeys.get_hotkey("Set Vehicles Invincible")
        configChanged = true
      end
    end

    -- Hotkey setter for setting vehicles vulnerable
    imgui.text("Set Vehicles Vulnerable Hotkey:")
    if HotkeysAvailable then
      local vulnerableHotkeyChanged = Hotkeys.hotkey_setter("Set Vehicles Vulnerable")
      if vulnerableHotkeyChanged then
        Config.Hotkeys["Set Vehicles Vulnerable"] = Hotkeys.get_hotkey("Set Vehicles Vulnerable")
        configChanged = true
      end
    end

    -- Save configuration if any hotkey has been changed
    if configChanged then
      Hotkeys.setup_hotkeys(Config.Hotkeys)
      save_config()
    end

    imgui.tree_pop()
  end
end)

-- Load configuration and apply hotkeys when script starts
load_config()
save_config()

return Config
