﻿# Provider Chat Guide

> Base URL: `{{base_url}}/api/v1/provider`
> All protected routes require: `Authorization: Bearer {token}`
> All requests/responses use `Content-Type: application/json`

---

## Overview

Chats are automatically created by the system — **the provider never creates a chat manually**.

| Trigger | When chat is created |
|---|---|
| Client creates a **Service Order** | Chat is created immediately when the order is placed |
| Provider **accepts** an **Urgent Order** | Chat is created on acceptance, and `chat_id` is sent via Socket to the client |

A chat is **closed** (`is_closed: true`) when the associated order is completed or cancelled. Sending a message to a closed chat returns a `422` error.

---

## REST API Endpoints

### 1. List Chats

**`GET /chats`** — Protected

Returns all chats the authenticated provider is a participant in, sorted by most recent activity. Includes unread message count per chat.

#### Query Parameters
| Param | Type | Default | Description |
|---|---|---|---|
| `per_page` | integer | 15 | Items per page |

#### Response
```json
{
    "status": "success",
    "message": "Data retrieved successfully",
    "data": [
        {
            "id": 7,
            "unread_count": 3,
            "other_user": {
                "id": 10,
                "full_name": "Ahmed Ali",
                "avatar": "https://..."
            },
            "latest_message": {
                "id": 55,
                "message": "هل انتهيت من المستند؟",
                "is_mine": false,
                "read_at": null,
                "created_at": 1725379200
            }
        }
    ],
    "links": { "first": "...", "last": "...", "prev": null, "next": null },
    "meta": { "current_page": 1, "last_page": 1, "per_page": 15, "total": 1 }
}
```

#### Response Field Reference
| Field | Type | Description |
|---|---|---|
| `id` | integer | Chat ID — use this to open the chat and send messages |
| `unread_count` | integer | Number of unread messages from the other participant |
| `other_user` | object | The client info (id, full_name, avatar) |
| `latest_message` | object\|null | Preview of last message, `null` if no messages yet |
| `latest_message.is_mine` | boolean | `true` if this provider sent the latest message |
| `latest_message.read_at` | integer\|null | Unix timestamp when client read it, `null` = unread |

---

### 2. Show Chat Messages

**`GET /chats/{chat_id}`** — Protected

Returns **paginated messages** in **reverse chronological order** (newest first). All unread messages from the client are marked as read automatically, and a `read_receipt` socket event is published.

#### Query Parameters
| Param | Type | Default | Description |
|---|---|---|---|
| `per_page` | integer | 20 | Messages per page |

#### Response
```json
{
    "status": "success",
    "message": "Data retrieved successfully",
    "data": [
        {
            "id": 55,
            "message": "هل انتهيت من المستند؟",
            "sender_data": {
                "id": 10,
                "full_name": "Ahmed Ali",
                "avatar": "https://..."
            },
            "is_mine": false,
            "read_at": 1725380000,
            "created_at": 1725379200
        },
        {
            "id": 54,
            "message": "سأرفع الملف قريباً",
            "sender_data": {
                "id": 42,
                "full_name": "أحمد المحامي",
                "avatar": "https://..."
            },
            "is_mine": true,
            "read_at": 1725379300,
            "created_at": 1725378000
        }
    ],
    "links": { "first": "...", "prev": null, "next": "..." },
    "meta": { "current_page": 1, "last_page": 3, "per_page": 20, "total": 55 }
}
```

#### Response Field Reference
| Field | Type | Description |
|---|---|---|
| `id` | integer | Message ID |
| `message` | string | Message text content |
| `sender_data` | object | Sender info (id, full_name, avatar) |
| `is_mine` | boolean | `true` if the authenticated provider sent this message |
| `read_at` | integer\|null | Unix timestamp the other party read it. `null` = unread |
| `created_at` | integer | Unix timestamp message was sent |

---

### 3. Send Message

**`POST /chats/{chat_id}/messages`** — Protected

Sends a new text message. After saving, publishes a real-time `message` event to the `nokhba-chat` Redis channel.

> **Blocked** if `is_closed: true` — returns `422`.

#### Request Body
```json
{
    "message": "سأكون متاحاً الساعة العاشرة صباحاً"
}
```

| Field | Required | Rules |
|---|---|---|
| `message` | YES | string, max 2000 characters |

#### Success Response — HTTP 201
```json
{
    "status": "success",
    "message": "Message sent successfully",
    "data": {
        "id": 56,
        "message": "سأكون متاحاً الساعة العاشرة صباحاً",
        "sender_data": {
            "id": 42,
            "full_name": "أحمد المحامي",
            "avatar": "https://..."
        },
        "is_mine": true,
        "read_at": null,
        "created_at": 1725380500
    }
}
```

#### Error Responses
| HTTP | Condition | Message |
|---|---|---|
| `404` | Chat not found or provider is not a participant | `"Chat not found"` |
| `422` | Chat is closed (order completed or cancelled) | `"This chat is closed. The service order has been completed."` |

---

## Real-Time / Socket Integration

The system uses **Redis Pub/Sub**. The Node.js socket server subscribes to Redis channels and forwards events to connected clients via Socket.IO.

### Redis Channels

| Channel | Purpose |
|---|---|
| `nokhba-chat` | Chat events: new messages and read receipts |
| `nokhba-urgent-orders` | Urgent order lifecycle events (including chat creation) |

---

### Channel: `nokhba-chat`

Subscribe to this channel and filter by `chat_id` to handle events for the relevant conversation.

---

#### Event Type: `message`

Fired when **any participant** sends a message. Both sender and receiver receive this event.

```json
{
    "chat_id": 7,
    "type": "message",
    "content": {
        "id": 56,
        "chat_id": 7,
        "sender_id": 42,
        "message": "سأكون متاحاً الساعة العاشرة صباحاً",
        "read_at": null,
        "created_at": "2026-09-08T12:00:00.000000Z",
        "sender": {
            "id": 42,
            "full_name": "أحمد المحامي",
            "avatar": "https://..."
        }
    }
}
```

**Frontend should:**
1. Check if `chat_id` matches the currently open chat.
2. If yes → append the message to the messages list.
3. If no → increment `unread_count` badge on that chat row.
4. If `content.sender_id !== currentUserId` → show a push/local notification.

---

#### Event Type: `read_receipt`

Fired when the other participant opens the chat (calls `GET /chats/{id}`), marking all your sent messages as read.

```json
{
    "chat_id": 7,
    "type": "read_receipt",
    "data": {
        "read_by": 10
    }
}
```

**Frontend should:**
1. Check if `chat_id` matches the currently open chat.
2. Update all messages where `is_mine: true` and `read_at: null` → show a double/blue tick.
3. `read_by` = the user ID of who read the messages.

---

### Channel: `nokhba-urgent-orders`

#### Event Type: `urgent_order_accepted`

> This event is sent **to the client** by the system when the provider accepts. It is listed here because it carries the `chat_id` that both parties will use.

When the provider calls `POST /urgent-orders/{id}/accept`, the system:
1. Creates the chat (`is_closed: false`)
2. Publishes this event to `nokhba-urgent-orders` with the `chat_id`

```json
{
    "user_id": 10,
    "type": "urgent_order_accepted",
    "data": {
        "order_id": 15,
        "chat_id": 7,
        "status": "accepted",
        "provider_data": {
            "id": 42,
            "full_name": "أحمد المحامي",
            "avatar": "https://...",
            "phone": "512345678",
            "avg_rating": 4.8,
            "reviews_count": 32
        }
    }
}
```

**Provider frontend should (after the accept API call succeeds):**
1. Navigate immediately to the chat screen using the `chat_id` returned from the accept response (or from this socket event).
2. Call `GET /chats/{chat_id}` to load the message history.
3. Enable the message input — chat is now open.

---

## Chat Lifecycle

```
[ Service Order Created ]
         |
         v
   Chat auto-created (is_closed = false)
         |
   Provider & Client exchange messages freely
         |
   Order Completed / Cancelled
         |
         v
   Chat closed (is_closed = true)
   Sending messages → 422 error


[ Urgent Order Created ]
         |
   Provider calls POST /urgent-orders/{id}/accept
         |
         v
   Chat auto-created (is_closed = false)
   "urgent_order_accepted" socket event → client gets chat_id
         |
   Provider & Client exchange messages freely
         |
   Urgent Order Completed / Cancelled
         |
         v
   Chat closed (is_closed = true)
```

---

## Frontend Integration Checklist

- [ ] Connect to Socket.IO on app launch
- [ ] Subscribe to `nokhba-chat` channel
- [ ] On `type: message` → append to open chat OR increment unread badge
- [ ] On `type: read_receipt` → update sent message read ticks
- [ ] Subscribe to `nokhba-urgent-orders`
- [ ] On `type: urgent_order_accepted` → navigate to chat using `data.chat_id`
- [ ] `GET /chats` → show conversation list with unread counts
- [ ] `GET /chats/{chat_id}` → load messages when opening chat (auto-marks as read)
- [ ] `POST /chats/{chat_id}/messages` → send message
- [ ] Handle `422` closed chat → hide message input, show "Chat closed" banner
- [ ] Paginate with `?per_page=20&page=N` when scrolling up for older messages
