-- PHASE9A_FIXED_NOON_BEGIN
do
    local phase9a_hook_file = io.open([[__DATA_PATH__\lua_phase9a_hook_loaded.txt]], "w")
    if phase9a_hook_file then
        phase9a_hook_file:write(
            "phase=9A\n" ..
            "fixedNoonHookLoaded=1\n" ..
            "weatherSyncLoaded=0\n" ..
            "playerSyncModified=0\n"
        )
        phase9a_hook_file:flush()
        phase9a_hook_file:close()
    end

    local phase9a_ok, phase9a_error = pcall(function()
        dofile([[__WIN64_PATH__\ue4ss\Mods\SurrounDeadOnline\Scripts\phase9a_fixed_noon.lua]])
    end)

    if not phase9a_ok then
        local phase9a_error_file = io.open([[__DATA_PATH__\lua_phase9a_hook_error.txt]], "w")
        if phase9a_error_file then
            phase9a_error_file:write(
                "phase=9A\n" ..
                "fixedNoonHookError=1\n" ..
                "message=" .. tostring(phase9a_error) .. "\n"
            )
            phase9a_error_file:flush()
            phase9a_error_file:close()
        end
    end
end
-- PHASE9A_FIXED_NOON_END
-- PHASE5G55_AUTOCONTINUE_BEGIN
do
    local phase5g55_hook_file = io.open([[__DATA_PATH__\lua_phase5g55_hook_started.txt]], "w")
    if phase5g55_hook_file then
        phase5g55_hook_file:write(
            "phase=5G.5.5.2\n" ..
            "bridgeHookStarted=1\n" ..
            "repair=client-b-auto-recovery\n"
        )
        phase5g55_hook_file:flush()
        phase5g55_hook_file:close()
    end

    local phase5g55_ok, phase5g55_error = pcall(function()
        dofile([[__WIN64_PATH__\ue4ss\Mods\SurrounDeadOnline\Scripts\phase5g55_autocontinue.lua]])
    end)

    if not phase5g55_ok then
        local phase5g55_error_file = io.open([[__DATA_PATH__\lua_phase5g55_hook_error.txt]], "w")
        if phase5g55_error_file then
            phase5g55_error_file:write(
                "phase=5G.5.5.2\n" ..
                "bridgeHookError=1\n" ..
                "message=" .. tostring(phase5g55_error) .. "\n"
            )
            phase5g55_error_file:flush()
            phase5g55_error_file:close()
        end
    end
end
-- PHASE5G55_AUTOCONTINUE_END
-- PHASE5H21_APPEARANCE_ONLY_BEGIN
do
    local phase5h21_hook_file = io.open([[__DATA_PATH__\lua_phase5h21_hook_loaded.txt]], "w")
    if phase5h21_hook_file then
        phase5h21_hook_file:write(
            "phase=5H.2.1\n" ..
            "appearanceOnlyHookLoaded=1\n" ..
            "movementPipelineReplaced=0\n"
        )
        phase5h21_hook_file:flush()
        phase5h21_hook_file:close()
    end

    local phase5h21_ok, phase5h21_error = pcall(function()
        dofile([[__WIN64_PATH__\ue4ss\Mods\SurrounDeadOnline\Scripts\phase5h21_appearance_only.lua]])
    end)

    if not phase5h21_ok then
        local phase5h21_error_file = io.open([[__DATA_PATH__\lua_phase5h21_hook_error.txt]], "w")
        if phase5h21_error_file then
            phase5h21_error_file:write(
                "phase=5H.2.1\n" ..
                "appearanceOnlyHookError=1\n" ..
                "message=" .. tostring(phase5h21_error) .. "\n"
            )
            phase5h21_error_file:flush()
            phase5h21_error_file:close()
        end
    end
end
-- PHASE5H21_APPEARANCE_ONLY_END
local MOD_NAME = "SurrounDeadOnline"
local dataPath = [[__DATA_PATH__]]
local loadedPath = dataPath .. "\\mod_loaded.txt"
local statePath = dataPath .. "\\local_state.tsv"
local remotePath = dataPath .. "\\remote_players.tsv"
local heartbeatPath = dataPath .. "\\game_heartbeat.txt"
local bridgePath = dataPath .. "\\Start-Bridge.ps1"

local UEHelpers = require("UEHelpers")
local lastCaptureError = ""
local lastRemoteCount = -1

local function log(message)
    print(string.format("[%s] %s\n", MOD_NAME, tostring(message)))
end

local function writeText(path, contents)
    local file, err = io.open(path, "w")
    if not file then return false, err end
    file:write(contents)
    file:flush()
    file:close()
    return true, nil
end

local function sanitize(value)
    local result = tostring(value or "")
    result = result:gsub("[\r\n\t|]", " ")
    if #result > 64 then result = result:sub(1, 64) end
    return result
end

local function getPawn()
    local controller = UEHelpers:GetPlayerController()
    if not controller or not controller:IsValid() then return nil end

    local pawn = nil
    local ok, value = pcall(function()
        if controller.Pawn then return controller.Pawn end
        return controller:GetPawn()
    end)
    if ok then pawn = value end
    if not pawn or not pawn:IsValid() then return nil end
    return pawn
end

local function captureLocalState()
    local pawn = getPawn()
    if not pawn then return end

    local location = pawn:K2_GetActorLocation()
    local rotation = pawn:K2_GetActorRotation()
    if not location or not rotation then return end

    local mapName = "world"
    local worldOk, world = pcall(function() return pawn:GetWorld() end)
    if worldOk and world and world:IsValid() then
        local nameOk, name = pcall(function()
            return world:GetFName():ToString()
        end)
        if nameOk and name then mapName = sanitize(name) end
    end

    local state = string.format(
        "%.3f\t%.3f\t%.3f\t%.3f\t%s",
        location.X,
        location.Y,
        location.Z,
        rotation.Yaw,
        mapName
    )

    writeText(statePath, state)
end

local function readRemotePlayers()
    local file = io.open(remotePath, "r")
    if not file then return {} end

    local players = {}
    for line in file:lines() do
        local id, name, x, y, z, yaw, mapName =
            line:match("([^\t]*)\t([^\t]*)\t([^\t]*)\t([^\t]*)\t([^\t]*)\t([^\t]*)\t?(.*)")
        if id and id ~= "" then
            table.insert(players, {
                id = id,
                name = name or "Survivor",
                x = tonumber(x) or 0,
                y = tonumber(y) or 0,
                z = tonumber(z) or 0,
                yaw = tonumber(yaw) or 0,
                map = mapName or "world"
            })
        end
    end

    file:close()
    return players
end

local function startBridge()
    local command = string.format(
        'cmd.exe /c start "" /min powershell.exe -NoLogo -NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File "%s"',
        bridgePath
    )
    local ok, result = pcall(os.execute, command)
    log("Phase 5G bridge launch requested. Result: " .. tostring(ok and result or result))
end

writeText(loadedPath, "Phase 5G safe client loaded\n")
log("Phase 5G dual-client capture client loaded.")
log("Lua handles capture/relay only; the compiled C++ mod renders the remote client.")
startBridge()

LoopAsync(180, function()
    writeText(heartbeatPath, tostring(os.time()))

    ExecuteInGameThread(function()
        local ok, err = pcall(captureLocalState)
        if not ok and tostring(err) ~= lastCaptureError then
            lastCaptureError = tostring(err)
            log("Player capture error: " .. lastCaptureError)
        end
    end)

    return false
end)

LoopAsync(500, function()
    local players = readRemotePlayers()
    if #players ~= lastRemoteCount then
        lastRemoteCount = #players
        log("Remote player count changed: " .. tostring(#players))
    end
    return false
end)

RegisterKeyBind(Key.F11, function()
    local players = readRemotePlayers()
    log("Connected remote players: " .. tostring(#players))

    for _, player in ipairs(players) do
        log(string.format(
            "%s at X=%.1f Y=%.1f Z=%.1f Yaw=%.1f",
            player.name,
            player.x,
            player.y,
            player.z,
            player.yaw
        ))
    end
end)

log("Phase 5G capture and relay loops registered. F11 lists the other real client.")

