================================================================================
       TAG App - Direct (One-on-One) Voice & Video Call Backend
                      Developer Documentation
================================================================================

1. INTRODUCTION
   This document describes the backend for one-on-one voice and video calls
   in the TAG application. Built on the same PHP/MySQL + Firestore architecture,
   it allows two users to initiate, accept, reject, and end calls. The system
   supports both audio‑only and video calls using a single set of endpoints,
   distinguished by a `call_type` field.

2. SYSTEM OVERVIEW
   - The PHP/MySQL layer manages call sessions and their lifecycle states:
     ringing → active (accepted) / missed / rejected / ended.
   - Real‑time WebRTC signaling (SDP offers/answers, ICE candidates) flows
     exclusively through Firebase Firestore. The REST API does not handle
     media or signaling.
   - The Flutter client manages media capture, peer connections, and Firestore
     subscriptions, while calling the API to transition call state.

3. DATABASE
   Table: `direct_video_calls` (existing, unchanged name)
   The table tracks all direct call sessions.

   Columns:
   - id             CHAR(36) PRIMARY KEY (UUID v4)
   - caller_user_id BIGINT UNSIGNED -> users.id
   - receiver_user_id BIGINT UNSIGNED -> users.id
   - call_type      ENUM('audio','video') NOT NULL DEFAULT 'video'  [NEW]
   - status         ENUM('ringing','active','ended','missed','rejected')
                    DEFAULT 'ringing'
   - started_at     TIMESTAMP NULL (set when accepted)
   - ended_at       TIMESTAMP NULL
   - created_at     TIMESTAMP DEFAULT CURRENT_TIMESTAMP
   - updated_at     TIMESTAMP NULL ON UPDATE CURRENT_TIMESTAMP

   SQL to add call_type (if not already present):
   ALTER TABLE `direct_video_calls`
   ADD COLUMN `call_type` enum('audio','video') NOT NULL DEFAULT 'video'
   AFTER `receiver_user_id`;

4. FILE STRUCTURE
   App/
   ├── Controllers/
   │   ├── DirectCallController.php   (renamed from DirectVideoCallController)
   │   └── VideoRoomController.php    (group rooms, unchanged)
   ├── Helpers/
   │   └── UuidGenerator.php
   ├── Models/
   │   ├── DirectCall.php             (renamed from DirectVideoCall)
   │   └── VideoRoom.php
   routes.php                         (updated: direct-calls routes)
   documentation_direct_call.txt      (this file)

5. MODEL: App/Models/DirectCall.php
   Provides static methods for database operations.

   Methods:
   - initiate($id, $callerId, $receiverId, $callType = 'video')
       Inserts a new ringing call record.
   - find($callId)
       Returns call array or null.
   - updateStatus($callId, $status, $endedAt = null)
       Changes call status; sets started_at when status = 'active'.
   - activeCallBetween($userA, $userB)
       Returns any active/ringing call between two users, preventing duplicate
       calls.

6. CONTROLLER: App/Controllers/DirectCallController.php
   Handles HTTP requests. All methods receive the authenticated user object.

   Methods:
   - call($user)
       POST /api/v1/direct-calls
       Request: { "receiver_user_id": <int>, "call_type": "audio"|"video" }
       Response: { "call_id", "caller_user_id", "receiver_user_id", "call_type" }
       Errors: 400 (invalid receiver), 409 (existing call)

   - show($user, $callId)
       GET /api/v1/direct-calls/{callId}
       Response: { "call": { ... } }
       Errors: 403, 404

   - accept($user, $callId)
       POST /api/v1/direct-calls/{callId}/accept
       Only the receiver may accept. Status must be 'ringing'.
       Errors: 400, 403, 404

   - reject($user, $callId)
       POST /api/v1/direct-calls/{callId}/reject
       Only the receiver may reject. Sets status to 'rejected' with ended_at.
       Errors: 400, 403, 404

   - end($user, $callId)
       POST /api/v1/direct-calls/{callId}/end
       Either participant can end. If call was 'ringing', status becomes 'missed';
       otherwise 'ended'. Sets ended_at.
       Errors: 400 (already ended), 403, 404

7. API ENDPOINTS (Base URL: https://tag.nsamaandcompany.com/tag_api/api/v1)

   POST   /direct-calls
          Initiate a call (voice or video). Requires JWT.

   GET    /direct-calls/{callId}
          Get call details.

   POST   /direct-calls/{callId}/accept
          Accept an incoming call (receiver only).

   POST   /direct-calls/{callId}/reject
          Reject an incoming call (receiver only).

   POST   /direct-calls/{callId}/end
          End a call (either participant).

   All endpoints return JSON in the standard TAG format:
   {
       "success": true,
       "message": "...",
       "data": { ... }
   }

8. FIRESTORE SIGNALING (Client-Side)
   The Flutter client uses Firebase Firestore to exchange WebRTC signaling data.
   Structure:

   direct_calls (collection)
     └── {callId} (document)
          ├── status: "ringing" | "active" | "ended" | "missed" | "rejected"
          ├── call_type: "audio" | "video"
          ├── caller_id: "<user ID>"
          ├── receiver_id: "<user ID>"
          └── signals (subcollection)
               ├── <caller_id> (document)
               │    ├── offer: <SDP string>
               │    ├── answer: <SDP string>
               │    └── iceCandidates: [ ... ]
               └── <receiver_id> (document)
                    ├── offer: ...
                    ├── answer: ...
                    └── iceCandidates: [ ... ]

   Client Flow:
   1. Caller calls POST /direct-calls → receives call_id.
   2. Caller creates Firestore document direct_calls/{call_id} with status
      "ringing" and call_type.
   3. Caller subscribes to signals/{receiver_id} for answer/ICE candidates.
   4. Caller creates RTCPeerConnection (audio only if call_type='audio'),
      generates SDP offer, writes to signals/{caller_id}.
   5. Receiver is notified (e.g., via FCM push or Firestore query).
   6. Receiver subscribes to signals/{caller_id} for the offer.
   7. To accept: calls POST /direct-calls/{callId}/accept, starts WebRTC.
   8. To reject: calls POST /direct-calls/{callId}/reject.
   9. Either can end by calling POST /direct-calls/{callId}/end.
   10. Both clean up Firestore documents after call ends.

   Firebase Auth is required to secure Firestore writes. The Flutter app
   should authenticate with Firebase (anonymous or user-mapped).

9. FLUTTER INTEGRATION NOTES
   - Use flutter_webrtc and cloud_firestore packages.
   - Initiate a call by passing receiver ID and call_type to the API.
   - For audio calls, request only audio: getUserMedia({'audio': true, 'video': false}).
   - Implement an incoming call UI that listens on Firestore for calls where
     receiver_id == myId and status == 'ringing'.
   - Handle permissions (camera/microphone) and call timeout (e.g., 30s -> missed).

10. TESTING
    API testing with Postman/cURL:
    - Obtain JWT via /auth/login.
    - POST /direct-calls with {"receiver_user_id":2, "call_type":"audio"}.
    - GET /direct-calls/{call_id} to inspect state.
    - As receiver, POST .../accept → verify status active.
    - As either, POST .../end → status becomes ended/missed.

    Integration test:
    - Two Flutter devices/emulators.
    - Test voice call (audio only), video call, rejection, busy detection.

11. ADDITIONAL CONSIDERATIONS
    - Busy detection: activeCallBetween() returns any active/ringing call
      between the two users, preventing overlapping calls.
    - Push notifications: Use FCM with tokens from user_devices.push_token.
    - Contacts/permissions: Optionally enforce that only contacts can call.
    - Cleanup: Clients should delete Firestore documents when call ends.

12. MIGRATION FROM PREVIOUS VERSION
    - Renamed DirectVideoCall -> DirectCall (model)
    - Renamed DirectVideoCallController -> DirectCallController
    - Route prefix changed from /video/calls to /direct-calls
    - Added call_type column to database (ALTER TABLE)
    - All existing video call functionality remains, but new endpoints
      should be used. Old routes can be kept temporarily for backward
      compatibility.

================================================================================
                         End of Documentation
================================================================================