# Calls

## **CallContact**

Initiates a phone call from one player to another.

```lua
---@param targetNumber string The phone number to call
---@param targetPlayerId number|nil Optional: Target player's source ID (auto-resolves if nil)
---@param callerNumber string The caller's phone number (can be payphone number)
---@param callerPlayerId number The caller's player source ID
---@param anonymousCall boolean|nil Optional: Whether to hide caller ID (default: false)
---@return table|nil Call data object with CallId, CallType, TargetData, etc. Returns nil if call fails
local callData = exports.yseries:CallContact(
    "0882222",      -- targetNumber
    nil,            -- targetPlayerId (nil will auto-resolve)
    "0889999",      -- callerNumber (can be non-existent number or even a string)
    source,         -- callerPlayerId (crucial to connect both players)
    false          -- anonymousCall (default: false)
)
```

**Validation Checks:**

* Validates caller player ID
* Checks if caller has airplane mode enabled
* Checks if caller is already in a call (allows loudspeaker participants)
* Checks if target can receive calls (dead, phone disabled, no phone item, etc.)
* Automatically removes target from loudspeaker if they're a participant

**Returns:**

```lua
{
    CallType = "outgoing",
    InCall = true,
    TargetData = {
        number = "0882222"
    },
    CallId = 17634,
    AnsweredCall = false,
    RecentCallId = nil  -- Will be created when call is answered
}
```

***

## **EndCall**

Ends an active phone call by call ID.

```lua
---@param callId number The call ID to end
---@return boolean True if call was ended successfully, false otherwise
local success = exports.yseries:EndCall(callId)

if success then
    print("Call ended successfully")
else
    print("Failed to end call - call not found")
end
```

**Note:** This will end the call for all participants and trigger cleanup events.

***

## **IsInCall**

Checks if a player is currently in a phone call and returns the call ID if they are.

```lua
---@param playerId number Player's source ID
---@return boolean True if player is in a call, false otherwise
---@return number|nil CallId if player is in a call, nil otherwise
local inCall, callId = exports.yseries:IsInCall(source)

if inCall then
    print("Player is currently in a call with CallId: " .. tostring(callId))
else
    print("Player is not in a call")
end
```

***

## **CanReceiveCalls**

Checks if a player can receive incoming calls. Returns `true` if player is not in a call, or if they're a loudspeaker participant.

```lua
---@param playerId number Player's source ID
---@return boolean True if player can receive calls, false otherwise
local canReceive = exports.yseries:CanReceiveCalls(source)

if canReceive then
    print("Player can receive calls")
else
    print("Player is busy and cannot receive calls")
end
```

**Use Case:** Check before initiating a call to ensure the target is available.

***

## **GetCallData**

Retrieves call data for a specific call ID. Returns an array of call data objects (one for each participant).

```lua
---@param callId number The call ID to retrieve data for
---@return table Array of call data objects
local callData = exports.yseries:GetCallData(17634)

if callData and #callData > 0 then
    for _, data in ipairs(callData) do
        print("Call Type: " .. data.CallType)
        print("Answered: " .. tostring(data.AnsweredCall))
        print("Call Start Time: " .. tostring(data.CallStartTime))
    end
end
```

**Returns:**

```lua
{
    {
        CallType = "outgoing",
        InCall = true,
        TargetData = {
            number = "0882222"
        },
        CallId = 17634,
        AnsweredCall = true,
        CallStartTime = 1763542085,
        RecentCallId = 1896
    },
    {
        CallType = "ongoing",
        InCall = true,
        TargetData = {
            number = "0889999",
            anonymous = false,
            isCompany = false
        },
        CallId = 17634,
        AnsweredCall = true,
        CallStartTime = 1763542085,
        RecentCallId = 1895
    }
}
```

***

## **RemovePlayerFromServerCall**

Removes a player from a call and cleans up their call state. Useful for handling disconnections or forced call termination.

```lua
---@param playerSourceId number Player's source ID to remove from call
exports.yseries:RemovePlayerFromServerCall(source)

-- This will:
-- 1. Clean up loudspeaker state
-- 2. Remove player from any loudspeaker they're participating in
-- 3. Clear their call data
```

**Note:** This is typically called automatically on player disconnect, but can be used manually if needed.

***

## **BlockContact**

Blocks or unblocks a phone number for a specific phone IMEI.

```lua
---@param contactData table Contact data with phoneNumber and isBlocked flag
---@param contactData.phoneNumber string Phone number to block/unblock
---@param contactData.isBlocked boolean True to block, false to unblock
---@param phoneImei string Phone IMEI to block the number for
---@return boolean True if operation was successful, false otherwise
local success = exports.yseries:BlockContact({
    phoneNumber = "0882222",
    isBlocked = true
}, phoneImei)

if success then
    print("Number blocked successfully")
end
```

***

## **GetBlockedNumbers**

Retrieves all blocked phone numbers for a specific phone IMEI.

```lua
---@param phoneImei string Phone IMEI to get blocked numbers for
---@return table Array of blocked phone numbers
local blockedNumbers = exports.yseries:GetBlockedNumbers(phoneImei)

for _, number in ipairs(blockedNumbers) do
    print("Blocked number: " .. number)
end
```

**Returns:**

```lua
{
    "0882222",
    "0883333",
    "0884444"
}
```

***

## **AddContact**

Adds a new contact to a player's phone. The contact will be automatically synced to the player's cached contacts if they are online, and a UI notification will be sent to update the state.

```lua
---@class ContactData
---@field number string The contact's phone number
---@field name string The contact's full name

---@param phoneNumber string The phone number to add the contact to
---@param data ContactData The contact data
---@return boolean success Whether the contact was added successfully
local success = exports.yseries:AddContact("01234567890", {
    number = "09876543210",
    name = "John Doe"
})

if success then
    print("Contact added successfully")
else
    print("Failed to add contact")
end
```

**Parameters:**

* `phoneNumber` (string) - The phone number of the player whose contact list the new contact will be added to
* `data` (ContactData) - The contact data object:
  * `number` (string, required) - The contact's phone number
  * `name` (string, required) - The contact's full name

**Behavior:**

* Stores the `name` field directly in the database
* If the player is online, their cached contacts (`PhoneData.Contacts`) will be automatically updated
* A UI notification will be sent to update the phone's UI state with the new contact
* Returns `true` if the contact was added successfully, `false` otherwise

**Validation:**

* Validates that `phoneNumber` is a valid string
* Validates that `data.number` and `data.name` are provided
* Checks if the phone IMEI exists for the given phone number
* Returns `false` if any validation fails or if the database insert fails

**Example:**

```lua
-- Add a contact with full name
exports.yseries:AddContact("01234567890", {
    number = "09876543210",
    name = "John Doe"
})

-- Add a contact with single name
exports.yseries:AddContact("01234567890", {
    number = "09876543210",
    name = "Jane"
})
```

***

## **AddRecentCall**

Adds a call to the recent calls list. This export should be used server-side only for security reasons, as it's vulnerable to manipulation if exposed to clients.

```lua
---@param toNumber string The phone number that was called
---@param phoneImei string The phone IMEI
---@param callType string Call type: "outgoing", "incoming", or "missed"
---@param anonymousCall boolean Whether the call was anonymous
---@return number|nil The insert ID of the recent call, or nil if failed
local insertId = exports.yseries:AddRecentCall("0882222", phoneImei, "outgoing", false)

if insertId then
    print("Recent call added with ID: " .. tostring(insertId))
else
    print("Failed to add recent call")
end
```

**Parameters:**

* `toNumber` (string, required) - The phone number that was called
* `phoneImei` (string, required) - The phone IMEI
* `callType` (string, required) - Call type: `"outgoing"`, `"incoming"`, or `"missed"`
* `anonymousCall` (boolean, optional) - Whether the call was anonymous (default: `false`)

**Returns:**

* `number|nil` - The insert ID of the recent call if successful, or `nil` if failed
