# Integrated & Interactive Contracts — Mobile Integration Guide

This document is the authoritative reference for integrating Integrated Contracts and Interactive Contracts into the mobile app. It covers service type detection, conditional UI flows, all relevant endpoints, payload structures, validation rules, and the stage lifecycle.

---

## Table of Contents

1. [Service Type Detection](#1-service-type-detection)
2. [New Static Page Type](#2-new-static-page-type)
3. [Party Lookup Endpoint](#3-party-lookup-endpoint)
4. [Creating a Service Order](#4-creating-a-service-order)
5. [Interactive Contract Stage Lifecycle](#5-interactive-contract-stage-lifecycle)
6. [Chat Attachments](#6-chat-attachments)

---

## 1. Service Type Detection

Every service object returned from the API includes a `service_type` string field. This is the **single source of truth** the Flutter app must use to determine which UI flow to render and which payload to submit.

### `service_type` Values

| Value                  | Arabic Label        | Description                                              |
|------------------------|---------------------|----------------------------------------------------------|
| `standard`             | خدمة عادية           | Standard order with a dynamic form (`form_data`)         |
| `integrated_case`      | قضية متكاملة         | Legal case order; uses dynamic form                      |
| `integrated_contract`  | عقد متكامل           | Contract order with parties + attachment + optional terms |
| `interactive_contract` | عقد تفاعلي           | Contract order with parties + attachment + stages        |
| `agency`               | خدمة الوكالة         | Agency singleton service                                 |

### Where `service_type` Appears

The field is included in every service response shape the mobile app consumes:

- **Catalog listing** — `GET /api/services` → `ServiceResource`
- **Service order list** — client and provider order list resources
- **Service order detail** — client and provider order show resources
- **Shared brief** — `ServiceBriefResource` embedded in nested responses

### ⚠️ Do Not Rely on Boolean Convenience Keys

Some service responses also include boolean fields such as `is_integrated_case` or `is_agency_service`. These are **legacy or admin-only convenience fields**. The mobile app **must not** branch logic on those booleans. Always inspect `service_type` directly.

The reasons:
- Boolean keys only cover a subset of types and will miss `integrated_contract` and `interactive_contract` entirely.
- New service types may be introduced in the future; `service_type` string matching is forward-compatible.
- Logic scattered across multiple booleans is fragile — a single `service_type` check is unambiguous.

---

## 2. New Static Page Type

A new static page type has been added specifically for Integrated Contracts:

| Page Type Key                | Arabic Label           |
|------------------------------|------------------------|
| `integrated_contract_terms`  | بنود عقد متكامل         |

**Usage:** When the user selects a service with `service_type = integrated_contract` or `service_type = interactive_contract`, the app must fetch and display this page, and the user must explicitly agree to its terms before the order creation form is shown (or before submission — per your UX design).

---

## 3. Party Lookup Endpoint

Before adding a party to an integrated or interactive contract order, the client can look up whether a registered user exists for that phone number. This pre-fills the form and avoids duplicate profile creation.

### Endpoint

```
POST /api/client/service/lookup-party
```

**Authentication:** Required (client token)

### Request Payload

| Field        | Type   | Required | Description                                         |
|--------------|--------|----------|-----------------------------------------------------|
| `phone_code` | string | ✅        | Country dial code (e.g. `+966`). Must be a valid country code. |
| `phone`      | string | ✅        | Local phone number (e.g. `501234567`).              |

> **Validation rule:** The client cannot look up their **own** phone number. The API will return a `422` validation error if the submitted phone matches the authenticated client's phone.

### Success Response — User Found

HTTP `200`

```json
{
  "status": "success",
  "message": "Party lookup completed",
  "data": {
    "id": 42,
    "full_name": "Ahmed Al-Otaibi",
    "avatar": "https://example.com/storage/avatars/42.jpg",
    "phone_code": "+966",
    "phone": "501234567"
  }
}
```

### Success Response — User Not Found

HTTP `200` with `data: null`

```json
{
  "status": "success",
  "message": "Party not found",
  "data": null
}
```

> **When `data` is `null`:** The user does not yet exist in the system. The client must still fill in all party fields manually (`full_name`, `national_id`, etc.). The backend will automatically create a new minimal user profile for that phone during order creation — no extra action is needed from the mobile side.

### Validation Error — Own Phone

HTTP `422`

```json
{
  "errors": {
    "phone": ["You cannot look up your own phone number as a contract party."]
  }
}
```

---

## 4. Creating a Service Order

**Endpoint:** `POST /api/client/service`

The required payload structure depends entirely on the `service_type` of the selected service. The app must read `service_type` from the catalog before navigating to the order form.

---

### 4.1 Standard / Integrated Case Orders

For `service_type = standard` or `service_type = integrated_case`.

#### Required Fields

| Field                       | Type    | Required | Notes                                                   |
|-----------------------------|---------|----------|---------------------------------------------------------|
| `service_id`                | integer | ✅        |                                                         |
| `provider_id` or `team_id`  | integer | ✅        | One of the two must be present                          |
| `scheduled_date`            | date    | ✅        | Format: `YYYY-MM-DD`, today or future                   |
| `scheduled_time`            | string  | ✅        | Format: `HH:MM` (24-hour), must not be in the past     |
| `payment_method`            | string  | ✅*       | `wallet` or `online`. Required unless `is_negotiating=true` |
| `brand`                     | string  | ✅*       | Required if `payment_method = online`                   |
| `transaction_id`            | string  | ✅*       | Required if `payment_method = online`. Must be unique.  |
| `is_negotiating`            | boolean | ❌        |                                                         |
| `negotiation_price`         | numeric | ✅*       | Required if `is_negotiating = true`                     |
| `broker_code`               | string  | ❌        | Must not be the client's own broker code                |
| `form_data`                 | array   | ✅        | Dynamic form answers. Min 1 item.                       |
| `form_data.*.field_key`     | string  | ✅        |                                                         |
| `form_data.*.answer`        | mixed   | ✅        |                                                         |

**Do not send** `parties`, `contract_attachment`, `contract_terms`, or `stages` for standard orders.

---

### 4.2 Integrated Contract Orders

For `service_type = integrated_contract`.

All base fields from section 4.1 apply (except `form_data`), plus:

| Field                        | Type    | Required | Notes                                                    |
|------------------------------|---------|----------|----------------------------------------------------------|
| `contract_attachment`        | integer | ✅        | Media ID of the uploaded contract document               |
| `contract_terms`             | string  | ❌        | Free-text contract terms (optional)                      |
| `parties`                    | array   | ✅        | Min 1, max 4 parties                                     |
| `parties.*.full_name`        | string  | ✅        | Max 255 characters                                       |
| `parties.*.national_id`      | string  | ✅        | Max 50 characters                                        |
| `parties.*.national_id_type` | string  | ✅        | One of the `NationalIdTypeEnum` values (see below)       |
| `parties.*.phone_code`       | string  | ✅        | Valid country dial code                                  |
| `parties.*.phone`            | string  | ✅        | Valid local phone number. **Must not match the client's own phone.** |

**Do not send** `form_data` or `stages`.

#### Party Phone Validation Rules

The backend validates every party phone on submission:
1. Phone format must be valid for the given country code.
2. No party may use the same phone number as the authenticated client.

These rules also apply to the lookup endpoint (see section 3).

#### `national_id_type` Enum Values

Fetch the valid values from the enum or the API lookup endpoint. Common values include `national_id` and `iqama`.

---

### 4.3 Interactive Contract Orders

For `service_type = interactive_contract`.

All requirements from section 4.2 (Integrated Contract) apply, plus:

| Field                  | Type    | Required | Notes                                        |
|------------------------|---------|----------|----------------------------------------------|
| `stages`               | array   | ✅        | Min 1 stage                                  |
| `stages.*.name`        | string  | ✅        | Stage name. Max 255 characters.              |
| `stages.*.end_date`    | date    | ✅        | Format: `YYYY-MM-DD`, today or future        |
| `stages.*.amount`      | numeric | ✅        | Stage payment amount. Min 0.                 |

**Do not send** `form_data`.

---

### 4.4 Summary: What to Send by Service Type

| Field                 | `standard` / `integrated_case` | `integrated_contract` | `interactive_contract` |
|-----------------------|:-------------------------------:|:---------------------:|:----------------------:|
| `form_data`           | ✅                               | ❌                     | ❌                      |
| `contract_attachment` | ❌                               | ✅                     | ✅                      |
| `contract_terms`      | ❌                               | optional              | optional               |
| `parties`             | ❌                               | ✅                     | ✅                      |
| `stages`              | ❌                               | ❌                     | ✅                      |

---

## 5. Interactive Contract Stage Lifecycle

Interactive contract orders follow a structured multi-party confirmation lifecycle.

### States Overview

```
pending
  └─► (provider accepts) ─► active
        └─► (provider starts) ─► in_progress
              └─► (all parties confirm each stage + client reconfirms)
                    └─► (final stage client-confirmed) ─► completed
```

### Step-by-Step

#### Step 1 — Order Created (`pending`)
The client submits the order. Status is `pending`.

#### Step 2 — Provider Accepts and Starts (`active` → `in_progress`)
The provider reviews and accepts the order (status → `active`), then starts work (status → `in_progress`). No further provider action is needed after this point — the provider does not confirm stages.

#### Step 3 — Party Stage Confirmation

Each party listed in the contract must confirm completion of the current stage.

```
POST /api/client/orders/service/{id}/stages/{stage}/party-confirm
```

| Parameter | Type    | Description                                         |
|-----------|---------|-----------------------------------------------------|
| `id`      | integer | Service order ID                                    |
| `stage`   | integer | Stage ID                                            |

- This endpoint is accessible to any user listed as a party on the order.
- A party can only confirm stages in sequence — previous stages must be completed first.
- A stage that is already confirmed cannot be confirmed again.

**Response errors:**

| Condition                         | Error Key                      |
|-----------------------------------|-------------------------------|
| Order is not interactive contract | `not_available`                |
| Caller is not a party             | `not_a_party`                  |
| Stage already completed           | `stage_already_complete`       |
| Previous stage not completed      | `previous_stages_incomplete`   |

#### Step 4 — Client Stage Reconfirmation

Once **all** parties have confirmed a stage, the main client (order creator) must officially reconfirm it.

```
POST /api/client/orders/service/{id}/stages/{stage}/confirm
```

Parameters are identical to the party-confirm endpoint.

> The client's confirmation is the final authoritative sign-off that marks the stage as fully complete.

#### Step 5 — Order Completion

When the client reconfirms the **last stage**, the order status automatically transitions to `completed`.

---

## 6. Chat Attachments

The chat system supports sending files (images, audio, video, and documents). Each message object in the chat response includes attachment metadata directly on the message.

### Chat Message Response Shape

```json
{
  "id": 11,
  "message": "Optional text",
  "sender_data": {
    "id": 3,
    "full_name": "Client Name",
    "avatar": "https://example.com/storage/avatars/3.jpg"
  },
  "is_mine": true,
  "read_at": null,
  "created_at": 1790686433,
  "attachment_data": {
    "url": "https://example.com/storage/files/document.pdf",
    "type": "file"
  }
}
```

### `attachment_data` Behavior

- **When there is no attachment:** `attachment_data` will be completely `null`. The message is purely a text message.
- **When there is an attachment:** `attachment_data` will be an object containing the `url` and the UI render `type`.

#### `type` Values (inside `attachment_data`)

| Value   | Description                                         |
|---------|-----------------------------------------------------|
| `image` | Image attachment                                    |
| `audio` | Audio attachment                                    |
| `video` | Video attachment                                    |
| `file`  | Generic file / document attachment                  |

**Note:** Always check if `attachment_data` is not `null` before attempting to render an attachment UI.

### Sending a Chat Message

To send a message with an attachment, use the standard chat message endpoint:

**Endpoint:** `POST /api/client/chats/{chat}/messages` *(and the equivalent provider route)*

#### Request Payload

| Field           | Type    | Required | Description                                                                 |
|-----------------|---------|----------|-----------------------------------------------------------------------------|
| `message`       | string  | ❌*       | Text message content. Required if `attachment_id` is not provided.          |
| `attachment_id` | integer | ❌*       | The Media ID of the uploaded file. Required if `message` is not provided.   |

**Important:** You must use the generic Media upload endpoint to upload the file first, then pass the returned ID as `attachment_id`. You can pass *both* `message` and `attachment_id` to send text along with a file.
