local config = require 'config.client'
local sharedConfig = require 'config.shared'
local WEAPONS = exports.qbx_core:GetWeapons()

---Configures and spawns a vehicle and teleports player to the driver seat.
---@param data { vehicleName: string, coords: vector4}
local function takeOutVehicle(data)
    local netId = lib.callback.await('qbx_ambulancejob:server:spawnVehicle', false, data.vehicleName, data.coords)

    local veh = lib.waitFor(function()
        if NetworkDoesEntityExistWithNetworkId(netId) then
            return NetToVeh(netId)
        end
    end)

    SetVehicleEngineOn(veh, true, true, true)

    local settings = config.vehicleSettings[data.vehicleName]
    if not settings then return end

    if settings.extras then
        qbx.setVehicleExtras(veh, settings.extras)
    end

    if settings.livery then
        SetVehicleLivery(veh, settings.livery)
    end
end

---Show the garage spawn menu
---@param vehicles AuthorizedVehicles
---@param coords vector4
local function showGarageMenu(vehicles, coords)
    local authorizedVehicles = vehicles[QBX.PlayerData.job.grade.level]
    local optionsMenu = {}
    for veh, label in pairs(authorizedVehicles) do
        optionsMenu[#optionsMenu + 1] = {
            title = label,
            onSelect = takeOutVehicle,
            args = {
                vehicleName = veh,
                coords = coords,
            }
        }
    end

    lib.registerContext({
        id = 'ambulance_garage_context_menu',
        title = locale('menu.amb_vehicles'),
        options = optionsMenu
    })

    lib.showContext('ambulance_garage_context_menu')
end

---Show patient's treatment menu.
---@param status string[]
local function showTreatmentMenu(status)
    local statusMenu = {}
    for i = 1, #status do
        statusMenu[i] = {
            title = status[i],
            event = 'hospital:client:TreatWounds',
        }
    end

    lib.registerContext({
        id = 'ambulance_status_context_menu',
        title = locale('menu.status'),
        options = statusMenu
    })

    lib.showContext('ambulance_status_context_menu')
end

---Check status of nearest player and show treatment menu.
---Intended to be invoked by client or server.
RegisterNetEvent('hospital:client:CheckStatus', function()
    local player = GetClosestPlayer()
    if not player then
        exports.qbx_core:Notify(locale('error.no_player'), 'error')
        return
    end

    local playerId = GetPlayerServerId(player)

    local status = lib.callback.await('qbx_ambulancejob:server:getPlayerStatus', false, playerId)
    if #status.injuries == 0 then
        exports.qbx_core:Notify(locale('success.healthy_player'), 'success')
        return
    end

    for hash in pairs(status.damageCauses) do
        TriggerEvent('chat:addMessage', {
            color = { 255, 0, 0 },
            multiline = false,
            args = { locale('info.status'), WEAPONS[hash].damagereason }
        })
    end

    if status.bleedLevel > 0 then
        TriggerEvent('chat:addMessage', {
            color = { 255, 0, 0 },
            multiline = false,
            args = { locale('info.status'), locale('info.is_status', status.bleedState) }
        })
    end

    showTreatmentMenu(status.injuries)
end)

---Use first aid on nearest player to revive them.
---Intended to be invoked by client or server.
RegisterNetEvent('hospital:client:RevivePlayer', function()
    local hasFirstAid = exports.ox_inventory:Search('count', 'firstaid') > 0
    if not hasFirstAid then
        exports.qbx_core:Notify(locale('error.no_firstaid'), 'error')
        return
    end

    local player = GetClosestPlayer()
    if not player then
        exports.qbx_core:Notify(locale('error.no_player'), 'error')
        return
    end

    -- Enhanced revival animation sequence
    lib.requestAnimDict(HealAnimDict, 5000)

    if lib.progressCircle({
        duration = 8000,
        position = 'bottom',
        label = locale('progress.revive'),
        useWhileDead = false,
        canCancel = true,
        disable = {
            move = true,
            car = true,
            combat = true,
            mouse = false,
        },
        anim = {
            dict = HealAnimDict,
            clip = HealAnim,
            flag = 1,
        },
    })
    then
                -- ARS-style multi-stage revival animation
        CreateThread(function()
            -- Stage 1: Kneel down and assess patient
            Wait(1000)

            -- Stage 2: Perform CPR
            lib.requestAnimDict('mini@cpr@char_a@cpr_str', 5000)
            TaskPlayAnim(cache.ped, 'mini@cpr@char_a@cpr_str', 'cpr_pumpchest', 8.0, -8.0, 4000, 1, 0, false, false, false)

            Wait(4000)

            -- Stage 3: Check pulse and finish
            lib.requestAnimDict('amb@medic@standing@kneel@base', 5000)
            TaskPlayAnim(cache.ped, 'amb@medic@standing@kneel@base', 'base', 8.0, -8.0, 2000, 1, 0, false, false, false)

            Wait(2000)
            ClearPedTasks(cache.ped)
        end)

        exports.qbx_core:Notify(locale('success.revived'), 'success')
        TriggerServerEvent('hospital:server:RevivePlayer', GetPlayerServerId(player))
    else
        StopAnimTask(cache.ped, HealAnimDict, HealAnim, 1.0)
        exports.qbx_core:Notify(locale('error.canceled'), 'error')
    end
end)

---Use bandage on nearest player to treat their wounds.
---Intended to be invoked by client or server.
RegisterNetEvent('hospital:client:TreatWounds', function()
    local hasBandage = exports.ox_inventory:Search('count', 'bandage') > 0
    if not hasBandage then
        exports.qbx_core:Notify(locale('error.no_bandage'), 'error')
        return
    end

    local player = GetClosestPlayer()
    if not player then
        exports.qbx_core:Notify(locale('error.no_player'), 'error')
        return
    end

    -- Enhanced treatment animation
    lib.requestAnimDict(HealAnimDict, 5000)

    if lib.progressCircle({
        duration = 6000,
        position = 'bottom',
        label = locale('progress.healing'),
        useWhileDead = false,
        canCancel = true,
        disable = {
            move = true,
            car = false,
            combat = true,
            mouse = false,
        },
        anim = {
            dict = HealAnimDict,
            clip = HealAnim,
            flag = 1,
        },
    })
    then
        StopAnimTask(cache.ped, HealAnimDict, HealAnim, 1.0)
        exports.qbx_core:Notify(locale('success.helped_player'), 'success')
        TriggerServerEvent('hospital:server:TreatWounds', GetPlayerServerId(player))
    else
        StopAnimTask(cache.ped, HealAnimDict, HealAnim, 1.0)
        exports.qbx_core:Notify(locale('error.canceled'), 'error')
    end
end)

---@param stashNumber integer id of stash to open
local function openStash(stashNumber)
    if not QBX.PlayerData.job.onduty then return end
    exports.ox_inventory:openInventory('stash', sharedConfig.locations.stash[stashNumber].name)
end

---Opens the hospital armory.
---@param armoryId integer id of armory to open
---@param stashId integer id of armory to open
local function openArmory(armoryId, stashId)
    if not QBX.PlayerData.job.onduty then return end
    exports.ox_inventory:openInventory('shop', { type = sharedConfig.locations.armory[armoryId].shopType, id = stashId })
end

---Teleports the player with a fade in/out effect
---@param coords vector3 | vector4
local function teleportPlayerWithFade(coords)
    DoScreenFadeOut(500)
    while not IsScreenFadedOut() do
        Wait(10)
    end

    SetEntityCoords(cache.ped, coords.x, coords.y, coords.z, false, false, false, false)
    if coords.w then
        SetEntityHeading(cache.ped, coords.w)
    end

    Wait(100)

    DoScreenFadeIn(1000)
end

---Teleports the player to main elevator
local function teleportToMainElevator()
    teleportPlayerWithFade(sharedConfig.locations.main[1])
end

---Teleports the player to roof elevator
local function teleportToRoofElevator()
    teleportPlayerWithFade(sharedConfig.locations.roof[1])
end

---Toggles the on duty status of the player.
local function toggleDuty()
    TriggerServerEvent('QBCore:ToggleDuty')
    TriggerServerEvent('police:server:UpdateBlips')
end

---Creates a zone that lets players store and retrieve job vehicles
---@param vehicles AuthorizedVehicles
---@param coords vector4
local function createGarage(vehicles, coords)
    lib.zones.box({
        coords = coords.xyz,
        size = vec3(5, 5, 2),
        rotation = coords.w,
        debug = config.debugPoly,
        onEnter = function()
            if QBX.PlayerData.job.type == 'ems' and QBX.PlayerData.job.onduty then
                lib.showTextUI(locale('text.veh_button'))
            end
        end,
        onExit = function()
            local _, text = lib.isTextUIOpen()
            if text == locale('text.veh_button') then lib.hideTextUI() end
        end,
        inside = function()
            if QBX.PlayerData.job.type == 'ems' and QBX.PlayerData.job.onduty and IsControlJustPressed(0, 38) then
                if cache.vehicle then
                    DeleteEntity(cache.vehicle)
            else
                showGarageMenu(vehicles, coords)
                end
            end
        end,
    })
end

---Creates air and land garages to spawn vehicles at for EMS personnel
CreateThread(function()
    -- Vehicle garages (only if enabled)
    if sharedConfig.features.vehicles and sharedConfig.locations.vehicle then
        for _, coords in pairs(sharedConfig.locations.vehicle) do
            createGarage(config.authorizedVehicles, coords)
        end
    end

    -- Helicopter garages (only if enabled)
    if sharedConfig.features.helicopters and sharedConfig.locations.helicopter then
        for _, coords in pairs(sharedConfig.locations.helicopter) do
            createGarage(config.authorizedHelicopters, coords)
        end
    end
end)

---Sets up duty toggle, stash, armory, and elevator interactions using either target or zones.
if config.useTarget then
    CreateThread(function()
        -- Duty system (only if enabled)
        if sharedConfig.features.dutySystem and sharedConfig.locations.duty then
            for i = 1, #sharedConfig.locations.duty do
            exports.ox_target:addBoxZone({
                name = 'duty' .. i,
                coords = sharedConfig.locations.duty[i],
                size = vec3(1.5, 1, 2),
                rotation = 71,
                debug = config.debugPoly,
                canInteract = function()
                    return QBX.PlayerData.job.type == 'ems'
                end,
                options = {
                    {
                        icon = 'fa fa-clipboard',
                        label = locale('text.duty'),
                        onSelect = toggleDuty,
                        distance = 2,
                        groups = 'ambulance',
                    }
                }
            })
            end
        end

        for i = 1, #sharedConfig.locations.stash do
            exports.ox_target:addBoxZone({
                name = 'stash' .. i,
                coords = sharedConfig.locations.stash[i].location,
                size = vec3(1, 1, 2),
                rotation = -20,
                debug = config.debugPoly,
                canInteract = function()
                    return QBX.PlayerData.job.type == 'ems'
                end,
                options = {
                    {
                        icon = 'fa fa-clipboard',
                        label = locale('text.pstash'),
                        onSelect = function()
                            openStash(i)
                        end,
                        distance = 2,
                        groups = 'ambulance',
                    }
                }
            })
        end

        for i = 1, #sharedConfig.locations.armory do
            for ii = 1, #sharedConfig.locations.armory[i].locations do
                exports.ox_target:addBoxZone({
                    name = 'armory' .. i .. ':' .. ii,
                    coords = sharedConfig.locations.armory[i].locations[ii],
                    size = vec3(1, 1, 2),
                    rotation = -20,
                    debug = config.debugPoly,
                    canInteract = function()
                        return QBX.PlayerData.job.type == 'ems'
                    end,
                    options = {
                        {
                            icon = 'fa fa-clipboard',
                            label = locale('text.armory'),
                            onSelect = function()
                                openArmory(i, ii)
                            end,
                            distance = 1.5,
                            groups = 'ambulance',
                        }
                    }
                })
            end
        end

        exports.ox_target:addBoxZone({
            name = 'roof1',
            coords = sharedConfig.locations.roof[1],
            size = vec3(1, 2, 2),
            rotation = -20,
            debug = config.debugPoly,
            options = {
                {
                    icon = 'fas fa-hand-point-down',
                    label = locale('text.el_main'),
                    onSelect = teleportToMainElevator,
                    distance = 1.5,
                    groups = 'ambulance',
                }
            }
        })

        exports.ox_target:addBoxZone({
            name = 'main1',
            coords = sharedConfig.locations.main[1],
            size = vec3(2, 1, 2),
            rotation = -20,
            debug = config.debugPoly,
            options = {
                {
                    icon = 'fas fa-hand-point-up',
                    label = locale('text.el_roof'),
                    onSelect = teleportToRoofElevator,
                    distance = 1.5,
                    groups = 'ambulance',
                }
            }
        })
    end)
else
    CreateThread(function()
        -- Duty system (only if enabled)
        if sharedConfig.features.dutySystem and sharedConfig.locations.duty then
            for i = 1, #sharedConfig.locations.duty do
            lib.zones.box({
                coords = sharedConfig.locations.duty[i],
                size = vec3(1, 1, 2),
                rotation = -20,
                debug = config.debugPoly,
                onEnter = function()
                    if QBX.PlayerData.job.type ~= 'ems' then return end
                    local label = QBX.PlayerData.job.onduty and locale('text.onduty_button') or locale('text.offduty_button')
                    lib.showTextUI(label)
                end,
                onExit = function()
                    local _, text = lib.isTextUIOpen()
                    if text == locale('text.onduty_button') or text == locale('text.offduty_button') then lib.hideTextUI() end
                end,
                inside = function()
                    if QBX.PlayerData.job.type ~= 'ems' then return end
                    OnKeyPress(toggleDuty)
                end,
            })
            end
        end

        for i = 1, #sharedConfig.locations.stash do
            lib.zones.box({
                coords = sharedConfig.locations.stash[i].location,
                size = vec3(1, 1, 2),
                rotation = -20,
                debug = config.debugPoly,
                onEnter = function()
                    if QBX.PlayerData.job.type ~= 'ems' or not QBX.PlayerData.job.onduty then return end
                    lib.showTextUI(locale('text.pstash_button'))
                    end,
                onExit = function()
                    local _, text = lib.isTextUIOpen()
                    if text == locale('text.pstash_button') then lib.hideTextUI() end
                end,
                inside = function()
                    if QBX.PlayerData.job.type ~= 'ems' then return end
                    OnKeyPress(function()
                        openStash(i)
                    end)
                end,
            })
        end

        for i = 1, #sharedConfig.locations.armory do
            for ii = 1, #sharedConfig.locations.armory[i].locations do
                lib.zones.box({
                    coords = sharedConfig.locations.armory[i].locations[ii],
                    size = vec3(1, 1, 2),
                    rotation = -20,
                    debug = config.debugPoly,
                    onEnter = function()
                        if QBX.PlayerData.job.type ~= 'ems' or not QBX.PlayerData.job.onduty then return end
                        lib.showTextUI(locale('text.armory_button'))
                        end,
                    onExit = function()
                        local _, text = lib.isTextUIOpen()
                        if text == locale('text.armory_button') then lib.hideTextUI() end
                    end,
                    inside = function()
                        if QBX.PlayerData.job.type ~= 'ems' then return end
                        OnKeyPress(function()
                            openArmory(i, ii)
                        end)
                    end,
                })
            end
        end

        lib.zones.box({
            coords = sharedConfig.locations.roof[1],
            size = vec3(1, 1, 2),
            rotation = -20,
            debug = config.debugPoly,
            onEnter = function()
                local label = QBX.PlayerData.job.onduty and locale('text.elevator_main') or locale('error.not_ems')
                lib.showTextUI(label)
            end,
            onExit = function()
                local _, text = lib.isTextUIOpen()
                if text == locale('text.elevator_main') or text == locale('error.not_ems') then lib.hideTextUI() end
            end,
            inside = function()
                OnKeyPress(teleportToMainElevator)
            end,
        })

        lib.zones.box({
            coords = sharedConfig.locations.main[1],
            size = vec3(1, 1, 2),
            rotation = -20,
            debug = config.debugPoly,
            onEnter = function()
                local label = QBX.PlayerData.job.onduty and locale('text.elevator_roof') or locale('error.not_ems')
                lib.showTextUI(label)
            end,
            onExit = function()
                local _, text = lib.isTextUIOpen()
                if text == locale('text.elevator_roof') or text == locale('error.not_ems') then lib.hideTextUI() end
            end,
            inside = function()
                OnKeyPress(teleportToRoofElevator)
            end,
        })
    end)
end
