Bridge.Database.AfterMigration("sky_phone", function()
local allowed_cancel_reasons = {
    changed_mind = true,
    driver_delay = true,
    emergency = true,
    other = true,
    wrong_pickup = true,
}
local quotes = {}
local online_drivers = {}
local operation_locks = {}
local services = {}

local function refresh_runtime_configuration()
    if Config.SkyRide.DistanceUnit ~= "kilometer" and Config.SkyRide.DistanceUnit ~= "mile" then
        error(("[sky_phone] Invalid SkyRide distance unit '%s'."):format(tostring(Config.SkyRide.DistanceUnit)))
    end

    local next_services = {}
    for index = 1, #Config.SkyRide.Services do
        local service = Config.SkyRide.Services[index]
        if service.Id ~= "taxi" and service.Id ~= "comfort" and service.Id ~= "xl" and service.Id ~= "premium" then
            error(("[sky_phone] Invalid SkyRide service class '%s'."):format(tostring(service.Id)))
        end
        if next_services[service.Id] then
            error(("[sky_phone] Duplicate SkyRide service class '%s'."):format(service.Id))
        end
        next_services[service.Id] = service
    end
    services = next_services
end

refresh_runtime_configuration()

AddEventHandler("sky_phone:configurator:serverUpdated", function()
    refresh_runtime_configuration()
end)

local ride_select = [[
    SELECT r.*,
        passenger.`owner_identifier` AS `passenger_identifier`,
        COALESCE(NULLIF(passenger.`display_name`, ''), r.`passenger_name`) AS `passenger_profile_name`,
        passenger_avatar.`url` AS `passenger_avatar_url`,
        driver.`owner_identifier` AS `driver_identifier`,
        COALESCE(NULLIF(driver.`display_name`, ''), r.`driver_name`) AS `driver_profile_name`,
        driver_avatar.`url` AS `driver_avatar_url`,
        UNIX_TIMESTAMP(r.`created_at`) AS `created_at_unix`,
        UNIX_TIMESTAMP(r.`updated_at`) AS `updated_at_unix`,
        UNIX_TIMESTAMP(r.`accepted_at`) AS `accepted_at_unix`,
        UNIX_TIMESTAMP(r.`arrived_at`) AS `arrived_at_unix`,
        UNIX_TIMESTAMP(r.`started_at`) AS `started_at_unix`,
        UNIX_TIMESTAMP(r.`completed_at`) AS `completed_at_unix`,
        UNIX_TIMESTAMP(r.`cancelled_at`) AS `cancelled_at_unix`
    FROM `sky_phone_skyride_rides` r
    INNER JOIN `sky_phone_skyride_profiles` passenger
        ON passenger.`id` = r.`passenger_profile_id`
    LEFT JOIN `sky_phone_media` passenger_avatar
        ON passenger_avatar.`id` = passenger.`avatar_media_id`
    LEFT JOIN `sky_phone_skyride_profiles` driver
        ON driver.`id` = r.`driver_profile_id`
    LEFT JOIN `sky_phone_media` driver_avatar
        ON driver_avatar.`id` = driver.`avatar_media_id`
]]

local function affected_rows(result)
    if type(result) == "number" then
        return result
    end
    return type(result) == "table" and tonumber(result.affectedRows) or 0
end

local function player_name(source)
    local firstname = Bridge.Framework.GetFirstname(source)
    local lastname = Bridge.Framework.GetLastname(source)
    local name = ((firstname or "") .. " " .. (lastname or "")):match("^%s*(.-)%s*$")
    if name == "" then
        name = GetPlayerName(source) or ("Player %s"):format(source)
    end
    return name:sub(1, 80)
end

local function get_player_coords(source)
    local ped = GetPlayerPed(source)
    if not ped or ped == 0 or not DoesEntityExist(ped) then
        return nil
    end
    local coords = GetEntityCoords(ped)
    return { x = coords.x, y = coords.y, z = coords.z }
end

local function distance_between(left, right)
    local x = left.x - right.x
    local y = left.y - right.y
    local z = left.z - right.z
    return math.sqrt((x * x) + (y * y) + (z * z))
end

local function is_near(source, location, radius)
    local coords = get_player_coords(source)
    return coords and distance_between(coords, location.coords) <= radius
end

local function validate_location(value)
    if type(value) ~= "table" or type(value.coords) ~= "table" then
        return nil
    end
    local label = type(value.label) == "string" and value.label:match("^%s*(.-)%s*$") or nil
    local label_length = label and utf8.len(label) or nil
    local x = tonumber(value.coords.x)
    local y = tonumber(value.coords.y)
    local z = tonumber(value.coords.z)
    local id = value.id
    if not label_length
        or label_length < 1
        or label_length > 80
        or not x
        or not y
        or not z
        or x ~= x
        or y ~= y
        or z ~= z
        or math.abs(x) > 10000.0
        or math.abs(y) > 10000.0
        or z < -1000.0
        or z > 3000.0
        or (id ~= nil and (type(id) ~= "string" or #id > 40 or not id:match("^[%w_-]+$")))
    then
        return nil
    end
    return {
        coords = { x = x, y = y, z = z },
        id = id,
        label = label,
    }
end

local function quick_locations()
    local result = {}
    for index = 1, #Config.SkyRide.QuickLocations do
        local location = Config.SkyRide.QuickLocations[index]
        result[index] = {
            coords = {
                x = location.Coords.x,
                y = location.Coords.y,
                z = location.Coords.z,
            },
            id = location.Id,
            label = location.Label,
        }
    end
    return result
end

local function generate_uuid()
    local rows = Bridge.Database.Query("SELECT UUID() AS `id`", {})
    local id = rows[1] and rows[1].id
    if type(id) ~= "string" then
        error("[sky_phone] Database did not generate a SkyRide id.")
    end
    return id
end

local function discard_quote_group(group)
    for quote_id, quote in pairs(quotes) do
        if quote.group == group then
            quotes[quote_id] = nil
        end
    end
end

local function require_profile(source)
    local session, error_response = SkyPhone.RequireSession(source)
    if not session then
        return nil, error_response
    end
    local identifier = Bridge.Framework.GetIdentifier(source)
    if type(identifier) ~= "string" or identifier == "" or #identifier > 80 then
        return nil, { success = false, error = "skyride_unavailable" }
    end
    Bridge.Database.Query([[
        INSERT IGNORE INTO `sky_phone_skyride_profiles` (`id`, `owner_identifier`)
        SELECT UUID(), ?
    ]], { identifier })
    local rows = Bridge.Database.Query([[
        SELECT profile.`id`, profile.`owner_identifier`, profile.`display_name`,
            profile.`avatar_media_id`, avatar.`url` AS `avatar_url`,
            UNIX_TIMESTAMP(profile.`created_at`) AS `created_at_unix`
        FROM `sky_phone_skyride_profiles` profile
        LEFT JOIN `sky_phone_media` avatar ON avatar.`id` = profile.`avatar_media_id`
        WHERE profile.`owner_identifier` = ?
        LIMIT 1
    ]], { identifier })
    if not rows[1] then
        error(("[sky_phone] Failed to load SkyRide profile for source %s."):format(tostring(source)))
    end
    return rows[1]
end

local function driver_eligible(source)
    local job = Bridge.Framework.GetJob(source)
    local minimum_grade = Config.SkyRide.DriverJobs[job.name]
    return minimum_grade ~= nil and (tonumber(job.grade) or 0) >= minimum_grade
end

local function driver_online(source, profile)
    local state = online_drivers[source]
    if not state or state.profile_id ~= profile.id or not driver_eligible(source) then
        online_drivers[source] = nil
        return false
    end
    return true
end

local function current_vehicle(source)
    local ped = GetPlayerPed(source)
    if not ped or ped == 0 or not DoesEntityExist(ped) then
        return nil
    end
    local entity = GetVehiclePedIsIn(ped, false)
    if not entity or entity == 0 or not DoesEntityExist(entity) then
        return nil
    end
    if GetPedInVehicleSeat(entity, -1) ~= ped then
        return nil
    end
    local vehicle = {
        color = "",
        model = "",
        plate = "",
    }
    vehicle.model = tostring(GetEntityModel(entity) or "")
    vehicle.plate = tostring(GetVehicleNumberPlateText(entity) or ""):match("^%s*(.-)%s*$"):sub(1, 16)
    return vehicle
end

local function profile_snapshot(source, profile)
    local rows = Bridge.Database.Query([[
        SELECT
            (SELECT COUNT(*)
                FROM `sky_phone_skyride_rides`
                WHERE `status` = 'completed'
                    AND (`passenger_profile_id` = ? OR `driver_profile_id` = ?)) AS `completed_rides`,
            (SELECT COUNT(*)
                FROM `sky_phone_skyride_rides`
                WHERE `status` = 'cancelled'
                    AND (`passenger_profile_id` = ? OR `driver_profile_id` = ?)) AS `cancelled_rides`,
            (SELECT AVG(`passenger_rating`)
                FROM `sky_phone_skyride_rides`
                WHERE `driver_profile_id` = ? AND `passenger_rating` IS NOT NULL) AS `rating`,
            (SELECT COALESCE(SUM(`payout_amount` + `tip_amount`), 0)
                FROM `sky_phone_skyride_rides`
                WHERE `driver_profile_id` = ?
                    AND `status` = 'completed'
                    AND DATE(`completed_at`) = CURRENT_DATE) AS `earnings_today`
    ]], { profile.id, profile.id, profile.id, profile.id, profile.id, profile.id })
    local stats = rows[1] or {}
    return {
        acceptanceRate = false,
        avatarMediaId = profile.avatar_media_id and tonumber(profile.avatar_media_id) or false,
        avatarUrl = profile.avatar_url or false,
        cancelledRides = tonumber(stats.cancelled_rides) or 0,
        completedRides = tonumber(stats.completed_rides) or 0,
        currency = Config.SkyRide.Currency,
        defaultPaymentMethod = Config.SkyRide.PaymentAccount,
        earningsToday = driver_eligible(source) and (tonumber(stats.earnings_today) or 0) or false,
        id = profile.id,
        memberSince = tonumber(profile.created_at_unix) or os.time(),
        name = profile.display_name or player_name(source),
        rating = math.floor(((tonumber(stats.rating) or 5.0) * 100) + 0.5) / 100,
    }
end

local function select_ride_rows(where_clause, parameters, limit)
    local values = {}
    for index = 1, #parameters do
        values[index] = parameters[index]
    end
    values[#values + 1] = limit
    return Bridge.Database.Query(
        ride_select .. " WHERE " .. where_clause .. " ORDER BY r.`updated_at` DESC, r.`id` DESC LIMIT ?",
        values
    )
end

local function profile_metrics(rows)
    local profile_ids = {}
    local seen = {}
    for index = 1, #rows do
        local row = rows[index]
        for _, profile_id in ipairs({ row.passenger_profile_id, row.driver_profile_id }) do
            if profile_id and not seen[profile_id] then
                seen[profile_id] = true
                profile_ids[#profile_ids + 1] = profile_id
            end
        end
    end
    if #profile_ids == 0 then
        return {}
    end
    local placeholders = {}
    for index = 1, #profile_ids do
        placeholders[index] = "?"
    end
    local metrics_rows = Bridge.Database.Query(([[
        SELECT profile.`id`,
            (SELECT AVG(ride.`passenger_rating`)
                FROM `sky_phone_skyride_rides` ride
                WHERE ride.`driver_profile_id` = profile.`id`
                    AND ride.`passenger_rating` IS NOT NULL) AS `rating`,
            (SELECT COUNT(*)
                FROM `sky_phone_skyride_rides` ride
                WHERE ride.`status` = 'completed'
                    AND (ride.`passenger_profile_id` = profile.`id`
                        OR ride.`driver_profile_id` = profile.`id`)) AS `trips`
        FROM `sky_phone_skyride_profiles` profile
        WHERE profile.`id` IN (%s)
    ]]):format(table.concat(placeholders, ", ")), profile_ids)
    local metrics = {}
    for index = 1, #metrics_rows do
        local row = metrics_rows[index]
        metrics[row.id] = {
            rating = math.floor(((tonumber(row.rating) or 5.0) * 100) + 0.5) / 100,
            trips = tonumber(row.trips) or 0,
        }
    end
    return metrics
end

local function source_for_identifier(identifier)
    if not identifier then
        return nil
    end
    for _, player_source in ipairs(Bridge.Framework.GetPlayers()) do
        local source = tonumber(player_source) or player_source
        if Bridge.Framework.GetIdentifier(source) == identifier then
            return source
        end
    end
    return nil
end

local function phone_number_for_source(source)
    local session = source and SkyPhone.RequireSession(source) or nil
    if not session then
        return nil
    end
    local device = SkyPhone.LoadDevice(session.imei)
    return device and device.phone_number or nil
end

local function online_source_for_identifier(identifier)
    if not identifier then
        return nil
    end
    for source, state in pairs(online_drivers) do
        if state.identifier == identifier and GetPlayerName(source) then
            return source
        end
    end
    return nil
end

local function person_dto(id, name, avatar_url, metrics)
    return {
        avatarUrl = avatar_url or false,
        id = id,
        name = name or "",
        rating = metrics and metrics.rating or 5.0,
        trips = metrics and metrics.trips or 0,
    }
end

local function ride_dtos(rows)
    local metrics = profile_metrics(rows)
    local result = {}
    for index = 1, #rows do
        local row = rows[index]
        local status = row.status == "completing" and "in_progress" or row.status
        local passenger = person_dto(
            row.passenger_profile_id,
            row.passenger_profile_name,
            row.passenger_avatar_url,
            metrics[row.passenger_profile_id]
        )
        local driver = false
        if row.driver_profile_id then
            driver = person_dto(
                row.driver_profile_id,
                row.driver_profile_name,
                row.driver_avatar_url,
                metrics[row.driver_profile_id]
            )
            driver.vehicle = {
                color = row.driver_vehicle_color or "",
                model = row.driver_vehicle_model or "",
                plate = row.driver_vehicle_plate or "",
            }
            if status == "accepted" or status == "arrived" or status == "in_progress" then
                local source = online_source_for_identifier(row.driver_identifier)
                local location = source and get_player_coords(source) or nil
                if location then
                    driver.location = location
                end
            end
        end
        local ride = {
            acceptedAt = row.accepted_at_unix and tonumber(row.accepted_at_unix) or nil,
            arrivedAt = row.arrived_at_unix and tonumber(row.arrived_at_unix) or nil,
            cancelledAt = row.cancelled_at_unix and tonumber(row.cancelled_at_unix) or nil,
            cancelledBy = row.cancelled_by,
            completedAt = row.completed_at_unix and tonumber(row.completed_at_unix) or nil,
            createdAt = tonumber(row.created_at_unix) or 0,
            currency = row.currency,
            destination = {
                coords = {
                    x = tonumber(row.destination_x) or 0.0,
                    y = tonumber(row.destination_y) or 0.0,
                    z = tonumber(row.destination_z) or 0.0,
                },
                label = row.destination_label,
            },
            distanceMeters = tonumber(row.distance_meters) or 0,
            driver = driver,
            durationSeconds = tonumber(row.duration_seconds) or 0,
            id = row.id,
            passenger = passenger,
            pickup = {
                coords = {
                    x = tonumber(row.pickup_x) or 0.0,
                    y = tonumber(row.pickup_y) or 0.0,
                    z = tonumber(row.pickup_z) or 0.0,
                },
                label = row.pickup_label,
            },
            price = tonumber(row.price) or 0,
            serviceClass = row.service_class,
            startedAt = row.started_at_unix and tonumber(row.started_at_unix) or nil,
            status = status,
            updatedAt = tonumber(row.updated_at_unix) or 0,
        }
        if status == "completed" then
            ride.finalPrice = tonumber(row.price) or 0
        end
        if row.passenger_rating then
            ride.rating = tonumber(row.passenger_rating)
        end
        result[index] = ride
    end
    return result
end

local function active_ride(profile_id)
    local rows = select_ride_rows([[
        (r.`passenger_profile_id` = ? OR r.`driver_profile_id` = ?)
            AND r.`status` IN ('searching','accepted','arrived','in_progress','completing')
    ]], { profile_id, profile_id }, 2)
    if #rows > 1 then
        Bridge.Debug(
            "error",
            "[sky_phone] SkyRide profile '%s' has multiple active rides.",
            tostring(profile_id)
        )
    end
    local rides = ride_dtos(rows)
    if rides[1] and rows[1] then
        local passenger_number = phone_number_for_source(source_for_identifier(rows[1].passenger_identifier))
        if passenger_number then
            rides[1].passenger.phoneNumber = passenger_number
        end
        if type(rides[1].driver) == "table" then
            local driver_number = phone_number_for_source(source_for_identifier(rows[1].driver_identifier))
            if driver_number then
                rides[1].driver.phoneNumber = driver_number
            end
        end
    end
    return rides[1], rows[1]
end

local function available_requests(profile_id)
    local rows = select_ride_rows([[
        r.`status` = 'searching' AND r.`passenger_profile_id` <> ?
    ]], { profile_id }, Config.SkyRide.HistoryLimit)
    return ride_dtos(rows)
end

local function ride_history(profile_id)
    local rows = select_ride_rows([[
        (r.`passenger_profile_id` = ? OR r.`driver_profile_id` = ?)
            AND r.`status` IN ('completed','cancelled')
    ]], { profile_id, profile_id }, Config.SkyRide.HistoryLimit)
    return ride_dtos(rows)
end

local function pending_rating(profile_id)
    local rows = select_ride_rows([[
        r.`passenger_profile_id` = ?
            AND r.`status` = 'completed'
            AND r.`passenger_rating` IS NULL
            AND r.`tip_status` = 'none'
    ]], { profile_id }, 1)
    local rides = ride_dtos(rows)
    return rides[1]
end

local function ride_by_id(ride_id)
    local rows = select_ride_rows("r.`id` = ?", { ride_id }, 1)
    local rides = ride_dtos(rows)
    return rides[1], rows[1]
end

local function process_pending_refund(row)
    if not row or (row.status ~= "payment_pending" and row.status ~= "cancelled") then
        return false
    end
    if row.refund_status == "completed" then
        if row.status ~= "payment_pending" then
            return true
        end
        local delete_success, delete_result = pcall(
            Bridge.Database.Query,
            [[
                DELETE FROM `sky_phone_skyride_rides`
                WHERE `id` = ? AND `status` = 'payment_pending'
                    AND `refund_status` = 'completed'
            ]],
            { row.id }
        )
        if not delete_success then
            Bridge.Debug(
                "error",
                "[sky_phone] Failed to remove refunded payment-pending SkyRide '%s': %s",
                row.id,
                tostring(delete_result)
            )
            return false
        end
        return true
    end
    if row.refund_status ~= "pending" then
        return false
    end
    local price = tonumber(row.price) or 0
    local passenger_source = source_for_identifier(row.passenger_identifier)
    if price > 0 and not passenger_source then
        return false
    end
    local claim_success, claim_result = pcall(
        Bridge.Database.Query,
        [[
            UPDATE `sky_phone_skyride_rides`
            SET `refund_status` = 'processing'
            WHERE `id` = ? AND `status` IN ('payment_pending','cancelled')
                AND `refund_status` = 'pending'
        ]],
        { row.id }
    )
    if not claim_success then
        Bridge.Debug(
            "error",
            "[sky_phone] Failed to claim pending refund for SkyRide '%s': %s",
            row.id,
            tostring(claim_result)
        )
        return false
    end
    if affected_rows(claim_result) ~= 1 then
        return false
    end
    local money_success = true
    local money_result = true
    if price > 0 then
        money_success, money_result = pcall(
            Bridge.Framework.AddMoney,
            passenger_source,
            Config.SkyRide.PaymentAccount,
            price
        )
    end
    if not money_success then
        Bridge.Debug(
            "error",
            "[sky_phone] Framework refund crashed for SkyRide '%s'; processing state prevents an automatic duplicate refund and requires manual reconciliation: %s",
            row.id,
            tostring(money_result)
        )
        return false
    end
    if not money_result then
        local reset_success, reset_result = pcall(
            Bridge.Database.Query,
            [[
                UPDATE `sky_phone_skyride_rides`
                SET `refund_status` = 'pending'
                WHERE `id` = ? AND `refund_status` = 'processing'
            ]],
            { row.id }
        )
        if not reset_success or affected_rows(reset_result) ~= 1 then
            Bridge.Debug(
                "error",
                "[sky_phone] Refund failed and its claim could not be reset for SkyRide '%s'; manual reconciliation is required.",
                row.id
            )
        end
        Bridge.Debug(
            "error",
            "[sky_phone] Framework refund failed for SkyRide '%s': %s",
            row.id,
            tostring(money_result)
        )
        return false
    end
    local finalize_success, finalize_result = pcall(
        Bridge.Database.Query,
        [[
            UPDATE `sky_phone_skyride_rides`
            SET `refund_status` = 'completed', `refunded_at` = CURRENT_TIMESTAMP
            WHERE `id` = ? AND `refund_status` = 'processing'
        ]],
        { row.id }
    )
    if not finalize_success or affected_rows(finalize_result) ~= 1 then
        Bridge.Debug(
            "error",
            "[sky_phone] Refund was paid but could not be finalized for SkyRide '%s'; processing state prevents an automatic duplicate refund.",
            row.id
        )
        return false
    end
    if passenger_source then
        TriggerClientEvent("sky_phone:banking:changed", passenger_source)
    end
    if row.status == "payment_pending" then
        local delete_success, delete_result = pcall(
            Bridge.Database.Query,
            [[
                DELETE FROM `sky_phone_skyride_rides`
                WHERE `id` = ? AND `status` = 'payment_pending'
                    AND `refund_status` = 'completed'
            ]],
            { row.id }
        )
        if not delete_success or affected_rows(delete_result) ~= 1 then
            Bridge.Debug(
                "error",
                "[sky_phone] Refunded payment-pending SkyRide '%s' could not be removed; recovery will retry cleanup.",
                row.id
            )
            return false
        end
    end
    return true
end

local function transition_tip_status(ride_id, expected_status, next_status)
    local update_success, update_result = pcall(
        Bridge.Database.Query,
        [[
            UPDATE `sky_phone_skyride_rides`
            SET `tip_status` = ?
            WHERE `id` = ? AND `tip_status` = ?
        ]],
        { next_status, ride_id, expected_status }
    )
    if not update_success or affected_rows(update_result) ~= 1 then
        Bridge.Debug(
            "error",
            "[sky_phone] Failed to move SkyRide '%s' tip state from '%s' to '%s'.",
            ride_id,
            expected_status,
            next_status
        )
        return false
    end
    return true
end

local function state_snapshot(source, profile, fields)
    local result = {}
    if fields.activeRide then
        result.activeRide = active_ride(profile.id) or false
    end
    if fields.availableRequests then
        result.availableRequests = driver_online(source, profile) and available_requests(profile.id) or {}
    end
    if fields.driverOnline then
        result.driverOnline = driver_online(source, profile)
    end
    if fields.history then
        result.history = ride_history(profile.id)
    end
    if fields.pendingRating then
        result.pendingRating = pending_rating(profile.id) or false
    end
    if fields.profile then
        result.profile = profile_snapshot(source, profile)
    end
    return result
end

local function push_update(source, fields)
    local profile = require_profile(source)
    if not profile then
        return
    end
    TriggerClientEvent("sky_phone:skyride:changed", source, state_snapshot(source, profile, fields))
end

local function push_participants(row, fields, excluded_source)
    for _, identifier in ipairs({ row.passenger_identifier, row.driver_identifier }) do
        local source = source_for_identifier(identifier)
        if source and source ~= excluded_source then
            push_update(source, fields)
        end
    end
end

local function push_available_requests(excluded_source)
    for source in pairs(online_drivers) do
        if source ~= excluded_source then
            push_update(source, { availableRequests = true })
        end
    end
end

local function run_locked(key, callback)
    if operation_locks[key] then
        return nil, { success = false, error = "rate_limited" }
    end
    operation_locks[key] = true
    local success, result = pcall(callback)
    operation_locks[key] = nil
    if not success then
        error(result)
    end
    return result
end

local function valid_ride_id(data)
    return type(data) == "table"
        and type(data.rideId) == "string"
        and #data.rideId == 36
        and data.rideId:match("^[%x%-]+$")
        and data.rideId
        or nil
end

local function transition_driver_ride(source, data, expected_statuses, next_status, timestamp_column, radius, location_kind)
    if not SkyPhone.AllowOperation(source, "skyride_action", Config.SkyRide.ActionsPerMinute, 60) then
        return { success = false, error = "rate_limited" }
    end
    local profile, error_response = require_profile(source)
    if not profile then
        return error_response
    end
    if not driver_online(source, profile) then
        return { success = false, error = "driver_offline" }
    end
    local ride_id = valid_ride_id(data)
    if not ride_id then
        return { success = false, error = "ride_not_found" }
    end
    local result, lock_error = run_locked("profile:" .. profile.id, function()
        local _, row = ride_by_id(ride_id)
        if not row then
            return { success = false, error = "ride_not_found" }
        end
        if row.driver_profile_id ~= profile.id then
            return { success = false, error = "not_ride_participant" }
        end
        if not expected_statuses[row.status] then
            return { success = false, error = "invalid_ride_status" }
        end
        local location = location_kind == "pickup" and {
            coords = {
                x = tonumber(row.pickup_x),
                y = tonumber(row.pickup_y),
                z = tonumber(row.pickup_z),
            },
        } or {
            coords = {
                x = tonumber(row.destination_x),
                y = tonumber(row.destination_y),
                z = tonumber(row.destination_z),
            },
        }
        if not is_near(source, location, radius) then
            return {
                success = false,
                error = location_kind == "pickup" and "driver_too_far" or "destination_too_far",
            }
        end
        if next_status == "in_progress" or next_status == "completing" then
            local passenger_source = source_for_identifier(row.passenger_identifier)
            if not passenger_source or not is_near(passenger_source, location, radius) then
                return { success = false, error = "passenger_too_far" }
            end
        end
        local status_placeholders = {}
        local parameters = { next_status }
        for status in pairs(expected_statuses) do
            status_placeholders[#status_placeholders + 1] = "?"
            parameters[#parameters + 1] = status
        end
        parameters[#parameters + 1] = ride_id
        parameters[#parameters + 1] = profile.id
        local update = Bridge.Database.Query(([[
            UPDATE `sky_phone_skyride_rides`
            SET `status` = ?, `%s` = CURRENT_TIMESTAMP
            WHERE `status` IN (%s) AND `id` = ? AND `driver_profile_id` = ?
        ]]):format(timestamp_column, table.concat(status_placeholders, ", ")), parameters)
        if affected_rows(update) ~= 1 then
            return { success = false, error = "invalid_ride_status" }
        end
        local _, updated_row = ride_by_id(ride_id)
        push_participants(updated_row, { activeRide = true }, source)
        return {
            success = true,
            data = state_snapshot(source, profile, { activeRide = true }),
        }
    end)
    return result or lock_error
end

Bridge.Callbacks.Register("sky_phone:skyride:bootstrap", function(source)
    if not SkyPhone.AllowOperation(source, "skyride_read", Config.SkyRide.ReadsPerMinute, 60) then
        return { success = false, error = "rate_limited" }
    end
    local profile, error_response = require_profile(source)
    if not profile then
        return error_response
    end
    local online = driver_online(source, profile)
    return {
        success = true,
        data = {
            activeRide = active_ride(profile.id) or false,
            availableRequests = online and available_requests(profile.id) or {},
            driverEligible = driver_eligible(source),
            driverOnline = online,
            history = ride_history(profile.id),
            pendingRating = pending_rating(profile.id) or false,
            profile = profile_snapshot(source, profile),
            quickLocations = quick_locations(),
        },
    }
end)

Bridge.Callbacks.Register("sky_phone:skyride:update-profile", function(source, data)
    if not SkyPhone.AllowOperation(source, "skyride_action", Config.SkyRide.ActionsPerMinute, 60) then
        return { success = false, error = "rate_limited" }
    end
    local profile, error_response = require_profile(source)
    if not profile then
        return error_response
    end
    local name = type(data) == "table" and type(data.name) == "string"
        and data.name:match("^%s*(.-)%s*$") or nil
    local name_length = name and utf8.len(name) or nil
    local avatar_media_id = type(data) == "table" and tonumber(data.avatarMediaId) or nil
    if not name_length
        or name_length < Config.SkyRide.ProfileNameMinLength
        or name_length > Config.SkyRide.ProfileNameMaxLength
    then
        return { success = false, error = "invalid_profile_name" }
    end
    if not avatar_media_id or avatar_media_id < 0 or avatar_media_id ~= math.floor(avatar_media_id) then
        return { success = false, error = "invalid_profile_image" }
    end
    if avatar_media_id > 0
        and not SkyPhoneMedia.ResolveOwnedMedia(source, tostring(avatar_media_id), "photo")
    then
        return { success = false, error = "invalid_profile_image" }
    end
    local result, lock_error = run_locked("profile:" .. profile.id, function()
        local update = Bridge.Database.Query([[
            UPDATE `sky_phone_skyride_profiles`
            SET `display_name` = ?, `avatar_media_id` = NULLIF(?, 0)
            WHERE `id` = ? AND `owner_identifier` = ?
        ]], { name, avatar_media_id, profile.id, profile.owner_identifier })
        if affected_rows(update) > 1 then
            error(("[sky_phone] SkyRide profile update affected multiple rows for '%s'."):format(profile.id))
        end
        local updated_profile = require_profile(source)
        local ride = active_ride(profile.id)
        if ride then
            push_participants(ride, { activeRide = true }, source)
        end
        push_available_requests(source)
        return {
            success = true,
            data = state_snapshot(source, updated_profile, { profile = true }),
        }
    end)
    return result or lock_error
end)

Bridge.Callbacks.Register("sky_phone:skyride:history", function(source)
    if not SkyPhone.AllowOperation(source, "skyride_read", Config.SkyRide.ReadsPerMinute, 60) then
        return { success = false, error = "rate_limited" }
    end
    local profile, error_response = require_profile(source)
    if not profile then
        return error_response
    end
    return { success = true, data = { items = ride_history(profile.id) } }
end)

Bridge.Callbacks.Register("sky_phone:skyride:quote", function(source, data)
    if not SkyPhone.AllowOperation(source, "skyride_quote", Config.SkyRide.QuotesPerMinute, 60) then
        return { success = false, error = "rate_limited" }
    end
    local profile, error_response = require_profile(source)
    if not profile then
        return error_response
    end
    local pickup = validate_location(data and data.pickup)
    local destination = validate_location(data and data.destination)
    if not pickup or not destination then
        return { success = false, error = "invalid_location" }
    end
    if not is_near(source, pickup, Config.SkyRide.PickupSelectionRadius) then
        return { success = false, error = "pickup_too_far" }
    end
    local custom_fare = data and data.customFare or nil
    if custom_fare ~= nil then
        local custom_service = type(custom_fare) == "table" and custom_fare.serviceClass or nil
        local custom_price = type(custom_fare) == "table" and custom_fare.price or nil
        if not Config.SkyRide.CustomFare.Enabled
            or type(custom_service) ~= "string"
            or not services[custom_service]
            or type(custom_price) ~= "number"
            or custom_price ~= custom_price
            or custom_price ~= math.floor(custom_price)
        then
            return { success = false, error = "invalid_custom_fare" }
        end
        custom_fare = {
            price = custom_price,
            service_class = custom_service,
        }
    end
    local direct_distance = distance_between(pickup.coords, destination.coords)
    local distance_meters = math.floor((direct_distance * Config.SkyRide.RouteDistanceMultiplier) + 0.5)
    if distance_meters < Config.SkyRide.MinimumDistanceMeters
        or distance_meters > Config.SkyRide.MaximumDistanceMeters
    then
        return { success = false, error = "invalid_route" }
    end
    local duration_seconds = math.max(
        60,
        math.floor((distance_meters / Config.SkyRide.AverageSpeedMetersPerSecond) + 0.5)
    )
    local now = os.time()
    local expires_at = now + Config.SkyRide.QuoteLifetimeSeconds
    local quote_group = generate_uuid()
    local options = {}
    local distance_unit = Config.SkyRide.DistanceUnit
    local distance_value = distance_meters / (distance_unit == "mile" and 1609.344 or 1000)
    for index = 1, #Config.SkyRide.Services do
        local service = Config.SkyRide.Services[index]
        local price_per_distance_unit = distance_unit == "mile"
            and service.PricePerMile
            or service.PricePerKilometer
        local calculated_price = math.floor(math.max(
            service.MinimumFare,
            service.BaseFare
                + (distance_value * price_per_distance_unit)
                + ((duration_seconds / 60) * service.PricePerMinute)
        ) + 0.5)
        local minimum_custom_price = math.floor(math.max(
            Config.SkyRide.CustomFare.MinimumPrice,
            service.MinimumFare,
            calculated_price * Config.SkyRide.CustomFare.MinimumCalculatedMultiplier
        ) + 0.5)
        local maximum_custom_price = math.floor(math.min(
            Config.SkyRide.CustomFare.MaximumPrice,
            calculated_price * Config.SkyRide.CustomFare.MaximumCalculatedMultiplier
        ) + 0.5)
        local uses_custom_fare = custom_fare and custom_fare.service_class == service.Id
        if uses_custom_fare
            and (custom_fare.price < minimum_custom_price or custom_fare.price > maximum_custom_price)
        then
            discard_quote_group(quote_group)
            return { success = false, error = "invalid_custom_fare" }
        end
        local price = uses_custom_fare and custom_fare.price or calculated_price
        local quote_id = quote_group .. ":" .. service.Id
        local option = {
            available = true,
            calculatedPrice = calculated_price,
            currency = Config.SkyRide.Currency,
            etaMinutes = service.EtaMinutes,
            fareMode = uses_custom_fare and "custom" or "calculated",
            maximumCustomPrice = maximum_custom_price,
            minimumCustomPrice = minimum_custom_price,
            price = price,
            pricePerDistanceUnit = price_per_distance_unit,
            quoteId = quote_id,
            seats = service.Seats,
            serviceClass = service.Id,
        }
        quotes[quote_id] = {
            destination = destination,
            distance_meters = distance_meters,
            duration_seconds = duration_seconds,
            expires_at = expires_at,
            group = quote_group,
            option = option,
            pickup = pickup,
            profile_id = profile.id,
            source = source,
        }
        options[index] = option
    end
    return {
        success = true,
        data = {
            destination = destination,
            distance = distance_value,
            distanceMeters = distance_meters,
            distanceUnit = distance_unit,
            durationSeconds = duration_seconds,
            expiresAt = expires_at,
            options = options,
            pickup = pickup,
        },
    }
end)

Bridge.Callbacks.Register("sky_phone:skyride:request", function(source, data)
    if not SkyPhone.AllowOperation(source, "skyride_action", Config.SkyRide.ActionsPerMinute, 60) then
        return { success = false, error = "rate_limited" }
    end
    local profile, error_response = require_profile(source)
    if not profile then
        return error_response
    end
    local quote_id = type(data) == "table" and data.quoteId or nil
    if type(quote_id) ~= "string" or #quote_id > 64 then
        return { success = false, error = "quote_not_found" }
    end
    local quote = quotes[quote_id]
    if not quote or quote.source ~= source or quote.profile_id ~= profile.id then
        return { success = false, error = "quote_not_found" }
    end
    if quote.expires_at <= os.time() then
        quotes[quote_id] = nil
        return { success = false, error = "quote_expired" }
    end
    if not is_near(source, quote.pickup, Config.SkyRide.PickupSelectionRadius) then
        return { success = false, error = "pickup_too_far" }
    end
    local result, lock_error = run_locked("profile:" .. profile.id, function()
        local pending_rows = select_ride_rows([[
            r.`passenger_profile_id` = ? AND r.`status` = 'payment_pending'
        ]], { profile.id }, 1)
        if active_ride(profile.id) or pending_rows[1] then
            return { success = false, error = "active_ride_exists" }
        end
        local ride_id = generate_uuid()
        local price = quote.option.price
        local payout = math.floor((price * Config.SkyRide.DriverPayoutPercent / 100) + 0.5)
        Bridge.Database.Query([[
            INSERT INTO `sky_phone_skyride_rides`
                (`id`, `passenger_profile_id`, `passenger_name`, `status`, `service_class`,
                    `pickup_label`, `pickup_x`, `pickup_y`, `pickup_z`,
                    `destination_label`, `destination_x`, `destination_y`, `destination_z`,
                    `distance_meters`, `duration_seconds`, `price`, `payout_amount`, `currency`)
            VALUES (?, ?, ?, 'payment_pending', ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
        ]], {
            ride_id,
            profile.id,
            profile.display_name or player_name(source),
            quote.option.serviceClass,
            quote.pickup.label,
            quote.pickup.coords.x,
            quote.pickup.coords.y,
            quote.pickup.coords.z,
            quote.destination.label,
            quote.destination.coords.x,
            quote.destination.coords.y,
            quote.destination.coords.z,
            quote.distance_meters,
            quote.duration_seconds,
            price,
            payout,
            quote.option.currency,
        })
        local charge_success = true
        local charge_result = true
        if price > 0 then
            charge_success, charge_result = pcall(
                Bridge.Framework.RemoveMoney,
                source,
                Config.SkyRide.PaymentAccount,
                price
            )
        end
        if not charge_success then
            discard_quote_group(quote.group)
            Bridge.Debug(
                "error",
                "[sky_phone] Fare debit crashed for SkyRide '%s'; payment state is ambiguous and requires manual reconciliation: %s",
                ride_id,
                tostring(charge_result)
            )
            return { success = false, error = "refund_failed" }
        end
        if not charge_result then
            local delete_success, delete_result = pcall(
                Bridge.Database.Query,
                "DELETE FROM `sky_phone_skyride_rides` WHERE `id` = ? AND `status` = 'payment_pending'",
                { ride_id }
            )
            if not delete_success or affected_rows(delete_result) ~= 1 then
                Bridge.Debug(
                    "error",
                    "[sky_phone] Failed to remove uncharged payment-pending SkyRide '%s'.",
                    ride_id
                )
            end
            return { success = false, error = "insufficient_funds" }
        end
        discard_quote_group(quote.group)
        if price > 0 then
            local capture_success, capture_result = pcall(
                Bridge.Database.Query,
                [[
                    UPDATE `sky_phone_skyride_rides`
                    SET `refund_status` = 'pending'
                    WHERE `id` = ? AND `status` = 'payment_pending'
                        AND `refund_status` = 'none'
                ]],
                { ride_id }
            )
            if not capture_success then
                Bridge.Debug(
                    "error",
                    "[sky_phone] Fare was charged but its recovery marker failed for SkyRide '%s': %s. Manual reconciliation is required.",
                    ride_id,
                    tostring(capture_result)
                )
                return { success = false, error = "refund_failed" }
            end
            if affected_rows(capture_result) ~= 1 then
                local refund_success, refund_result = pcall(
                    Bridge.Framework.AddMoney,
                    source,
                    Config.SkyRide.PaymentAccount,
                    price
                )
                if refund_success and refund_result then
                    local delete_success, delete_result = pcall(
                        Bridge.Database.Query,
                        "DELETE FROM `sky_phone_skyride_rides` WHERE `id` = ? AND `status` = 'payment_pending'",
                        { ride_id }
                    )
                    if delete_success and affected_rows(delete_result) == 1 then
                        TriggerClientEvent("sky_phone:banking:changed", source)
                        return { success = false, error = "request_failed" }
                    end
                end
                Bridge.Debug(
                    "error",
                    "[sky_phone] Fare recovery failed before activating SkyRide '%s'. Manual reconciliation is required.",
                    ride_id
                )
                return { success = false, error = "refund_failed" }
            end
        end
        local update_success, update = pcall(Bridge.Database.Query, [[
            UPDATE `sky_phone_skyride_rides`
            SET `status` = 'searching', `refund_status` = 'none'
            WHERE `id` = ? AND `status` = 'payment_pending'
                AND `refund_status` = ?
        ]], { ride_id, price > 0 and "pending" or "none" })
        if not update_success or affected_rows(update) ~= 1 then
            local load_success, _, pending_row = pcall(ride_by_id, ride_id)
            if load_success and pending_row and pending_row.status == "searching" then
                update_success = true
            elseif load_success and pending_row and price > 0 and pending_row.refund_status == "pending" then
                local refunded = process_pending_refund(pending_row)
                if not refunded then
                    return { success = false, error = "refund_failed" }
                end
                return { success = false, error = "request_failed" }
            elseif price > 0 then
                Bridge.Debug(
                    "error",
                    "[sky_phone] Could not verify fare recovery after SkyRide '%s' activation failed; manual reconciliation is required.",
                    ride_id
                )
                return { success = false, error = "refund_failed" }
            else
                local delete_success, delete_result = pcall(
                    Bridge.Database.Query,
                    [[
                        DELETE FROM `sky_phone_skyride_rides`
                        WHERE `id` = ? AND `status` = 'payment_pending'
                            AND `refund_status` = 'none'
                    ]],
                    { ride_id }
                )
                if not delete_success or affected_rows(delete_result) ~= 1 then
                    Bridge.Debug(
                        "error",
                        "[sky_phone] Failed to clean payment-pending SkyRide '%s' after request activation failed.",
                        ride_id
                    )
                end
                if not update_success then
                    Bridge.Debug(
                        "error",
                        "[sky_phone] Failed to activate SkyRide '%s': %s",
                        ride_id,
                        tostring(update)
                    )
                end
                return { success = false, error = "request_failed" }
            end
        end
        TriggerClientEvent("sky_phone:banking:changed", source)
        push_available_requests(source)
        return {
            success = true,
            data = state_snapshot(source, profile, {
                activeRide = true,
                availableRequests = true,
            }),
        }
    end)
    return result or lock_error
end)

Bridge.Callbacks.Register("sky_phone:skyride:set-driver-status", function(source, data)
    if not SkyPhone.AllowOperation(source, "skyride_action", Config.SkyRide.ActionsPerMinute, 60) then
        return { success = false, error = "rate_limited" }
    end
    local profile, error_response = require_profile(source)
    if not profile then
        return error_response
    end
    if type(data) ~= "table" or type(data.online) ~= "boolean" then
        return { success = false, error = "invalid_driver_status" }
    end
    if data.online and not driver_eligible(source) then
        return { success = false, error = "driver_not_eligible" }
    end
    local _, ride_row = active_ride(profile.id)
    if not data.online and ride_row and ride_row.driver_profile_id == profile.id then
        return { success = false, error = "active_ride_exists" }
    end
    if data.online and ride_row and ride_row.passenger_profile_id == profile.id and not ride_row.driver_profile_id then
        return { success = false, error = "active_ride_exists" }
    end
    online_drivers[source] = data.online and {
        identifier = profile.owner_identifier,
        profile_id = profile.id,
    } or nil
    return {
        success = true,
        data = state_snapshot(source, profile, {
            driverOnline = true,
            availableRequests = true,
        }),
    }
end)

Bridge.Callbacks.Register("sky_phone:skyride:accept", function(source, data)
    if not SkyPhone.AllowOperation(source, "skyride_action", Config.SkyRide.ActionsPerMinute, 60) then
        return { success = false, error = "rate_limited" }
    end
    local profile, error_response = require_profile(source)
    if not profile then
        return error_response
    end
    if not driver_online(source, profile) then
        return { success = false, error = "driver_offline" }
    end
    local ride_id = valid_ride_id(data)
    if not ride_id then
        return { success = false, error = "ride_not_found" }
    end
    local result, lock_error = run_locked("profile:" .. profile.id, function()
        if active_ride(profile.id) then
            return { success = false, error = "active_ride_exists" }
        end
        local _, row = ride_by_id(ride_id)
        if not row then
            return { success = false, error = "ride_not_found" }
        end
        if row.status ~= "searching" then
            return { success = false, error = "invalid_ride_status" }
        end
        if row.passenger_profile_id == profile.id then
            return { success = false, error = "not_ride_participant" }
        end
        local vehicle = current_vehicle(source)
        if not vehicle then
            return { success = false, error = "driver_vehicle_required" }
        end
        local update = Bridge.Database.Query([[
            UPDATE `sky_phone_skyride_rides`
            SET `driver_profile_id` = ?, `driver_name` = ?, `status` = 'accepted',
                `driver_vehicle_model` = ?, `driver_vehicle_color` = ?, `driver_vehicle_plate` = ?,
                `accepted_at` = CURRENT_TIMESTAMP
            WHERE `id` = ? AND `status` = 'searching' AND `driver_profile_id` IS NULL
        ]], {
            profile.id,
            profile.display_name or player_name(source),
            vehicle.model,
            vehicle.color,
            vehicle.plate,
            ride_id,
        })
        if affected_rows(update) ~= 1 then
            return { success = false, error = "invalid_ride_status" }
        end
        local _, updated_row = ride_by_id(ride_id)
        push_participants(updated_row, { activeRide = true, availableRequests = true }, source)
        push_available_requests(source)
        return {
            success = true,
            data = state_snapshot(source, profile, {
                activeRide = true,
                availableRequests = true,
            }),
        }
    end)
    return result or lock_error
end)

Bridge.Callbacks.Register("sky_phone:skyride:arrive", function(source, data)
    return transition_driver_ride(
        source,
        data,
        { accepted = true },
        "arrived",
        "arrived_at",
        Config.SkyRide.ArrivalRadius,
        "pickup"
    )
end)

Bridge.Callbacks.Register("sky_phone:skyride:start", function(source, data)
    return transition_driver_ride(
        source,
        data,
        { arrived = true },
        "in_progress",
        "started_at",
        Config.SkyRide.ArrivalRadius,
        "pickup"
    )
end)

Bridge.Callbacks.Register("sky_phone:skyride:complete", function(source, data)
    if not SkyPhone.AllowOperation(source, "skyride_action", Config.SkyRide.ActionsPerMinute, 60) then
        return { success = false, error = "rate_limited" }
    end
    local profile, error_response = require_profile(source)
    if not profile then
        return error_response
    end
    if not driver_online(source, profile) then
        return { success = false, error = "driver_offline" }
    end
    local ride_id = valid_ride_id(data)
    if not ride_id then
        return { success = false, error = "ride_not_found" }
    end
    local result, lock_error = run_locked("ride:" .. ride_id, function()
        local _, row = ride_by_id(ride_id)
        if not row then
            return { success = false, error = "ride_not_found" }
        end
        if row.driver_profile_id ~= profile.id then
            return { success = false, error = "not_ride_participant" }
        end
        if row.status ~= "in_progress" then
            return { success = false, error = "invalid_ride_status" }
        end
        local destination = {
            coords = {
                x = tonumber(row.destination_x),
                y = tonumber(row.destination_y),
                z = tonumber(row.destination_z),
            },
        }
        if not is_near(source, destination, Config.SkyRide.CompletionRadius) then
            return { success = false, error = "destination_too_far" }
        end
        local passenger_source = source_for_identifier(row.passenger_identifier)
        if not passenger_source or not is_near(passenger_source, destination, Config.SkyRide.CompletionRadius) then
            return { success = false, error = "passenger_too_far" }
        end
        local completing = Bridge.Database.Query([[
            UPDATE `sky_phone_skyride_rides`
            SET `status` = 'completing'
            WHERE `id` = ? AND `driver_profile_id` = ? AND `status` = 'in_progress'
        ]], { ride_id, profile.id })
        if affected_rows(completing) ~= 1 then
            return { success = false, error = "invalid_ride_status" }
        end
        local payout = tonumber(row.payout_amount) or 0
        local payout_success = true
        local payout_result = true
        if payout > 0 then
            payout_success, payout_result = pcall(
                Bridge.Framework.AddMoney,
                source,
                Config.SkyRide.PaymentAccount,
                payout
            )
        end
        if not payout_success then
            Bridge.Debug(
                "error",
                "[sky_phone] Driver payout crashed for SkyRide '%s'; completing state prevents an ambiguous retry and requires manual reconciliation: %s",
                ride_id,
                tostring(payout_result)
            )
            return { success = false, error = "payout_failed" }
        end
        if not payout_result then
            local reset_success, reset_result = pcall(Bridge.Database.Query, [[
                UPDATE `sky_phone_skyride_rides`
                SET `status` = 'in_progress'
                WHERE `id` = ? AND `status` = 'completing'
            ]], { ride_id })
            if not reset_success or affected_rows(reset_result) ~= 1 then
                Bridge.Debug(
                    "error",
                    "[sky_phone] Driver payout failed and SkyRide '%s' could not be restored to in-progress.",
                    ride_id
                )
            end
            return { success = false, error = "payout_failed" }
        end
        local completed_success, completed = pcall(Bridge.Database.Query, [[
            UPDATE `sky_phone_skyride_rides`
            SET `status` = 'completed', `completed_at` = CURRENT_TIMESTAMP,
                `paid_out_at` = CURRENT_TIMESTAMP
            WHERE `id` = ? AND `status` = 'completing'
        ]], { ride_id })
        if not completed_success then
            Bridge.Debug(
                "error",
                "[sky_phone] SkyRide '%s' completion query crashed after payout; completing state blocks an ambiguous retry and requires manual reconciliation: %s",
                ride_id,
                tostring(completed)
            )
            return { success = false, error = "payout_failed" }
        end
        if affected_rows(completed) ~= 1 then
            local compensation_success = true
            local compensation_result = true
            if payout > 0 then
                compensation_success, compensation_result = pcall(
                    Bridge.Framework.RemoveMoney,
                    source,
                    Config.SkyRide.PaymentAccount,
                    payout
                )
            end
            if compensation_success and compensation_result then
                local reset_success, reset_result = pcall(Bridge.Database.Query, [[
                    UPDATE `sky_phone_skyride_rides`
                    SET `status` = 'in_progress', `completed_at` = NULL, `paid_out_at` = NULL
                    WHERE `id` = ? AND `status` = 'completing'
                ]], { ride_id })
                if reset_success and affected_rows(reset_result) == 1 then
                    if payout > 0 then
                        TriggerClientEvent("sky_phone:banking:changed", source)
                    end
                    Bridge.Debug(
                        "error",
                        "[sky_phone] Compensated driver payout after SkyRide '%s' completion could not be finalized.",
                        ride_id
                    )
                    return { success = false, error = "payout_failed" }
                end
                Bridge.Debug(
                    "error",
                    "[sky_phone] Driver payout was compensated but SkyRide '%s' could not be restored; manual reconciliation is required.",
                    ride_id
                )
                return { success = false, error = "payout_failed" }
            end
            Bridge.Debug(
                "error",
                "[sky_phone] Failed to compensate payout for unfinalized SkyRide '%s'; completing state prevents an automatic duplicate payout: %s",
                ride_id,
                tostring(compensation_result)
            )
            return { success = false, error = "payout_failed" }
        end
        TriggerClientEvent("sky_phone:banking:changed", source)
        local _, updated_row = ride_by_id(ride_id)
        push_participants(updated_row, {
            activeRide = true,
            history = true,
            pendingRating = true,
            profile = true,
        }, source)
        return {
            success = true,
            data = state_snapshot(source, profile, {
                activeRide = true,
                history = true,
                pendingRating = true,
                profile = true,
            }),
        }
    end)
    return result or lock_error
end)

Bridge.Callbacks.Register("sky_phone:skyride:cancel", function(source, data)
    if not SkyPhone.AllowOperation(source, "skyride_action", Config.SkyRide.ActionsPerMinute, 60) then
        return { success = false, error = "rate_limited" }
    end
    local profile, error_response = require_profile(source)
    if not profile then
        return error_response
    end
    local ride_id = valid_ride_id(data)
    if not ride_id then
        return { success = false, error = "ride_not_found" }
    end
    local reason = data.reason
    if reason ~= nil and (type(reason) ~= "string" or not allowed_cancel_reasons[reason]) then
        return { success = false, error = "invalid_cancel_reason" }
    end
    local result, lock_error = run_locked("ride:" .. ride_id, function()
        local _, row = ride_by_id(ride_id)
        if not row then
            return { success = false, error = "ride_not_found" }
        end
        local role
        if row.passenger_profile_id == profile.id then
            role = "passenger"
        elseif row.driver_profile_id == profile.id then
            role = "driver"
        else
            return { success = false, error = "not_ride_participant" }
        end
        if row.status ~= "searching"
            and row.status ~= "accepted"
            and row.status ~= "arrived"
            and row.status ~= "in_progress"
        then
            return { success = false, error = "invalid_ride_status" }
        end
        if row.status == "searching" and role ~= "passenger" then
            return { success = false, error = "not_ride_participant" }
        end
        local update = Bridge.Database.Query([[
            UPDATE `sky_phone_skyride_rides`
            SET `status` = 'cancelled', `cancelled_by` = ?, `cancel_reason` = ?,
                `cancelled_at` = CURRENT_TIMESTAMP, `refund_status` = 'pending'
            WHERE `id` = ? AND `status` IN ('searching','accepted','arrived','in_progress')
                AND `refund_status` = 'none'
        ]], { role, reason, ride_id })
        if affected_rows(update) ~= 1 then
            return { success = false, error = "invalid_ride_status" }
        end
        local _, updated_row = ride_by_id(ride_id)
        if not process_pending_refund(updated_row) then
            Bridge.Debug(
                "info",
                "[sky_phone] Refund for cancelled SkyRide '%s' remains queued for server recovery.",
                ride_id
            )
        end
        _, updated_row = ride_by_id(ride_id)
        push_participants(updated_row, {
            activeRide = true,
            availableRequests = true,
            history = true,
            pendingRating = true,
            profile = true,
        }, source)
        push_available_requests(source)
        return {
            success = true,
            data = state_snapshot(source, profile, {
                activeRide = true,
                availableRequests = true,
                history = true,
                pendingRating = true,
                profile = true,
            }),
        }
    end)
    return result or lock_error
end)

Bridge.Callbacks.Register("sky_phone:skyride:rate", function(source, data)
    if not SkyPhone.AllowOperation(source, "skyride_action", Config.SkyRide.ActionsPerMinute, 60) then
        return { success = false, error = "rate_limited" }
    end
    local profile, error_response = require_profile(source)
    if not profile then
        return error_response
    end
    local ride_id = valid_ride_id(data)
    if not ride_id then
        return { success = false, error = "ride_not_found" }
    end
    local rating = tonumber(data.rating)
    local tip = tonumber(data.tip) or 0
    local comment = type(data.comment) == "string" and data.comment:match("^%s*(.-)%s*$") or ""
    local comment_length = utf8.len(comment)
    if not rating or rating ~= math.floor(rating) or rating < 1 or rating > 5 then
        return { success = false, error = "invalid_rating" }
    end
    if not tip or tip ~= math.floor(tip) or tip < 0 or tip > Config.SkyRide.MaximumTip then
        return { success = false, error = "invalid_tip" }
    end
    if not comment_length or comment_length > Config.SkyRide.RatingCommentMaxLength then
        return { success = false, error = "invalid_comment" }
    end
    local result, lock_error = run_locked("ride:" .. ride_id, function()
        local _, row = ride_by_id(ride_id)
        if not row then
            return { success = false, error = "ride_not_found" }
        end
        if row.passenger_profile_id ~= profile.id then
            return { success = false, error = "not_ride_participant" }
        end
        if row.status ~= "completed" or row.passenger_rating ~= nil or row.tip_status ~= "none" then
            return { success = false, error = "invalid_ride_status" }
        end
        local driver_source = source_for_identifier(row.driver_identifier)
        if tip > 0 and not driver_source then
            return { success = false, error = "driver_unavailable" }
        end
        if not transition_tip_status(ride_id, "none", "processing") then
            return { success = false, error = "invalid_ride_status" }
        end
        if tip > 0 then
            local debit_success, debit_result = pcall(
                Bridge.Framework.RemoveMoney,
                source,
                Config.SkyRide.PaymentAccount,
                tip
            )
            if not debit_success then
                transition_tip_status(ride_id, "processing", "failed")
                Bridge.Debug(
                    "error",
                    "[sky_phone] Passenger tip debit crashed for SkyRide '%s'; manual reconciliation is required: %s",
                    ride_id,
                    tostring(debit_result)
                )
                return { success = false, error = "tip_failed" }
            end
            if not debit_result then
                transition_tip_status(ride_id, "processing", "none")
                return { success = false, error = "insufficient_funds" }
            end
            local credit_success, credit_result = pcall(
                Bridge.Framework.AddMoney,
                driver_source,
                Config.SkyRide.PaymentAccount,
                tip
            )
            if not credit_success then
                transition_tip_status(ride_id, "processing", "failed")
                Bridge.Debug(
                    "error",
                    "[sky_phone] Driver tip credit crashed for SkyRide '%s'; retry is blocked for manual reconciliation: %s",
                    ride_id,
                    tostring(credit_result)
                )
                return { success = false, error = "tip_failed" }
            end
            if not credit_result then
                local refund_success, refund_result = pcall(
                    Bridge.Framework.AddMoney,
                    source,
                    Config.SkyRide.PaymentAccount,
                    tip
                )
                if refund_success and refund_result then
                    transition_tip_status(ride_id, "processing", "none")
                    TriggerClientEvent("sky_phone:banking:changed", source)
                else
                    transition_tip_status(ride_id, "processing", "failed")
                    Bridge.Debug(
                        "error",
                        "[sky_phone] Passenger refund after rejected driver tip credit is ambiguous or failed for SkyRide '%s'; retry is blocked for manual reconciliation: %s",
                        ride_id,
                        tostring(refund_result)
                    )
                end
                return { success = false, error = "tip_failed" }
            end
        end
        local update_success, update = pcall(Bridge.Database.Query, [[
            UPDATE `sky_phone_skyride_rides`
            SET `passenger_rating` = ?, `rating_comment` = ?, `tip_amount` = ?,
                `tip_status` = 'completed'
            WHERE `id` = ? AND `passenger_profile_id` = ?
                AND `status` = 'completed' AND `passenger_rating` IS NULL
                AND `tip_status` = 'processing'
        ]], { rating, comment, tip, ride_id, profile.id })
        if not update_success then
            Bridge.Debug(
                "error",
                "[sky_phone] Rating query crashed after tip transfer for SkyRide '%s'; processing state blocks an ambiguous retry and requires manual reconciliation: %s",
                ride_id,
                tostring(update)
            )
            return { success = false, error = "tip_failed" }
        end
        if affected_rows(update) ~= 1 then
            if tip == 0 then
                transition_tip_status(ride_id, "processing", "none")
                return { success = false, error = "tip_failed" }
            end
            local driver_debit_success, driver_debit_result = pcall(
                Bridge.Framework.RemoveMoney,
                driver_source,
                Config.SkyRide.PaymentAccount,
                tip
            )
            if not driver_debit_success or not driver_debit_result then
                transition_tip_status(ride_id, "processing", "failed")
                Bridge.Debug(
                    "error",
                    "[sky_phone] Rating persistence failed and driver tip debit was ambiguous or rejected for SkyRide '%s'; passenger refund was not attempted and manual reconciliation is required: %s",
                    ride_id,
                    tostring(driver_debit_result)
                )
                return { success = false, error = "tip_failed" }
            end
            TriggerClientEvent("sky_phone:banking:changed", driver_source)
            local passenger_refund_success, passenger_refund_result = pcall(
                Bridge.Framework.AddMoney,
                source,
                Config.SkyRide.PaymentAccount,
                tip
            )
            if passenger_refund_success and passenger_refund_result then
                TriggerClientEvent("sky_phone:banking:changed", source)
                transition_tip_status(ride_id, "processing", "none")
                Bridge.Debug(
                    "error",
                    "[sky_phone] Compensated rating persistence failure for SkyRide '%s'.",
                    ride_id
                )
            else
                transition_tip_status(ride_id, "processing", "failed")
                Bridge.Debug(
                    "error",
                    "[sky_phone] Driver tip was removed but passenger refund was ambiguous or rejected for SkyRide '%s'; manual reconciliation is required: %s",
                    ride_id,
                    tostring(passenger_refund_result)
                )
            end
            return { success = false, error = "tip_failed" }
        end
        if tip > 0 then
            TriggerClientEvent("sky_phone:banking:changed", source)
            TriggerClientEvent("sky_phone:banking:changed", driver_source)
        end
        local _, updated_row = ride_by_id(ride_id)
        push_participants(updated_row, { history = true, pendingRating = true, profile = true }, source)
        return {
            success = true,
            data = state_snapshot(source, profile, {
                history = true,
                pendingRating = true,
                profile = true,
            }),
        }
    end)
    return result or lock_error
end)

AddEventHandler("playerDropped", function()
    local player_source = source
    online_drivers[player_source] = nil
    for quote_id, quote in pairs(quotes) do
        if quote.source == player_source then
            quotes[quote_id] = nil
        end
    end
end)

CreateThread(function()
    while true do
        Wait(30000)
        local now = os.time()
        for quote_id, quote in pairs(quotes) do
            if quote.expires_at <= now or not GetPlayerName(quote.source) then
                quotes[quote_id] = nil
            end
        end
        for source in pairs(online_drivers) do
            if not GetPlayerName(source) then
                online_drivers[source] = nil
            end
        end
    end
end)

CreateThread(function()
    local reconciliation_rows = Bridge.Database.Query([[
        SELECT
            SUM(`refund_status` = 'processing') AS `processing_refunds`,
            SUM(`tip_status` IN ('processing','failed')) AS `unresolved_tips`,
            SUM(`status` = 'completing') AS `unresolved_payouts`,
            SUM(`status` = 'payment_pending' AND `refund_status` = 'none') AS `ambiguous_payments`
        FROM `sky_phone_skyride_rides`
    ]], {})
    local reconciliation = reconciliation_rows[1] or {}
    if (tonumber(reconciliation.processing_refunds) or 0) > 0
        or (tonumber(reconciliation.unresolved_tips) or 0) > 0
        or (tonumber(reconciliation.unresolved_payouts) or 0) > 0
        or (tonumber(reconciliation.ambiguous_payments) or 0) > 0
    then
        Bridge.Debug(
            "error",
            "[sky_phone] SkyRide has unresolved cross-system payments (refunds=%s, tips=%s, payouts=%s, ambiguous fares=%s); manual reconciliation is required.",
            tostring(reconciliation.processing_refunds or 0),
            tostring(reconciliation.unresolved_tips or 0),
            tostring(reconciliation.unresolved_payouts or 0),
            tostring(reconciliation.ambiguous_payments or 0)
        )
    end
    while true do
        local recovery_success, recovery_rows = pcall(
            Bridge.Database.Query,
            ride_select .. (([[
                WHERE r.`refund_status` IN ('pending','completed')
                    AND (
                        r.`status` = 'cancelled'
                        OR (
                            r.`status` = 'payment_pending'
                            AND r.`updated_at` <= DATE_SUB(
                                CURRENT_TIMESTAMP,
                                INTERVAL %d SECOND
                            )
                        )
                    )
                ORDER BY r.`updated_at` ASC
                LIMIT 50
            ]]):format(math.floor(Config.SkyRide.PaymentPendingRecoverySeconds)))
        )
        if recovery_success then
            for index = 1, #recovery_rows do
                process_pending_refund(recovery_rows[index])
            end
        else
            Bridge.Debug(
                "error",
                "[sky_phone] SkyRide refund recovery query failed: %s",
                tostring(recovery_rows)
            )
        end
        Wait(math.floor(Config.SkyRide.RecoveryIntervalSeconds * 1000))
    end
end)

AddEventHandler("onResourceStop", function(resource_name)
    if resource_name ~= GetCurrentResourceName() then
        return
    end
    quotes = {}
    online_drivers = {}
    operation_locks = {}
end)
end)
