<?php
/**
 * Unified Chat AJAX Dispatcher
 * File: ajax/chat.php
 */

// Buffer ALL output so stray PHP warnings/notices never corrupt JSON
ob_start();

session_start();

// Suppress PHP notices/warnings from appearing in the JSON stream
error_reporting(0);
ini_set('display_errors', 0);

header('Content-Type: application/json');

if (!isset($_SESSION['user_id'])) {
    ob_end_clean();
    echo json_encode(['success' => false, 'message' => 'Unauthorized']);
    exit;
}

require_once '../layouts/dbconn.php';

// Verify DB connection came through
if (!isset($conn) || !$conn) {
    ob_end_clean();
    echo json_encode(['success' => false, 'message' => 'Database connection failed.']);
    exit;
}

$me     = (int)$_SESSION['user_id'];
$action = $_POST['action'] ?? $_GET['action'] ?? '';

// Wrap everything in try-catch so no fatal error ever returns broken JSON
try {

switch ($action) {

    // ─────────────────────────────────────────────────────────────────────────
    // GET_CONVERSATIONS: list all conversations for current user with unread counts
    // ─────────────────────────────────────────────────────────────────────────
    case 'get_conversations':
        $sql = "
            SELECT

                c.conversation_id,
                c.conversation_type,
                c.title,
                c.last_message_at,
                -- Last message preview
                (SELECT m.message_text FROM chat_messages m
                 WHERE m.conversation_id = c.conversation_id AND m.is_deleted = 0
                 ORDER BY m.sent_at DESC LIMIT 1)                AS last_message,
                (SELECT m.sent_at FROM chat_messages m
                 WHERE m.conversation_id = c.conversation_id AND m.is_deleted = 0
                 ORDER BY m.sent_at DESC LIMIT 1)                AS last_msg_time,
                -- Unread count
                (SELECT COUNT(*) FROM chat_messages m2
                 WHERE m2.conversation_id = c.conversation_id
                   AND m2.is_deleted = 0
                   AND m2.sender_id <> ?
                   AND m2.sent_at > COALESCE(cp.last_read_at, '1970-01-01'))
                                                                 AS unread_count,
                -- Other participant name (for direct chats)
                (SELECT u2.full_name FROM chat_participants cp2
                 JOIN users u2 ON cp2.user_id = u2.user_id
                 WHERE cp2.conversation_id = c.conversation_id
                   AND cp2.user_id <> ?
                 LIMIT 1)                                        AS other_name,
                (SELECT ur.role_name FROM chat_participants cp3
                 JOIN users u3 ON cp3.user_id = u3.user_id
                 JOIN user_roles ur ON u3.role_id = ur.role_id
                 WHERE cp3.conversation_id = c.conversation_id
                   AND cp3.user_id <> ?
                 LIMIT 1)                                        AS other_role
            FROM chat_conversations c
            JOIN chat_participants cp ON c.conversation_id = cp.conversation_id
            WHERE cp.user_id = ? AND c.is_active = 1
            ORDER BY COALESCE(c.last_message_at, c.created_at) DESC
            LIMIT 50
        ";
        $stmt = $conn->prepare($sql);
        $stmt->bind_param("iiii", $me, $me, $me, $me);
        $stmt->execute();
        $rows = $stmt->get_result()->fetch_all(MYSQLI_ASSOC);
        ob_end_clean();
        echo json_encode(['success' => true, 'conversations' => $rows]);
        break;

    // ─────────────────────────────────────────────────────────────────────────
    // GET_MESSAGES: fetch messages for a conversation (paginated, polling)
    // ─────────────────────────────────────────────────────────────────────────
    case 'get_messages':
        $conv_id    = (int)($_POST['conversation_id'] ?? 0);
        $after_id   = (int)($_POST['after_message_id'] ?? 0); // 0 = load last 50
        $load_more  = isset($_POST['load_more']);              // load older messages

        if (!$conv_id) { echo json_encode(['success' => false, 'message' => 'Missing conversation_id']); exit; }

        // Access check
        $ac = $conn->prepare("SELECT participant_id FROM chat_participants WHERE conversation_id=? AND user_id=?");
        $ac->bind_param("ii", $conv_id, $me);
        $ac->execute();
        if (!$ac->get_result()->fetch_assoc()) {
            echo json_encode(['success' => false, 'message' => 'Not a participant.']);
            exit;
        }

        if ($load_more) {
            $before_id = (int)($_POST['before_message_id'] ?? PHP_INT_MAX);
            $sql = "
                SELECT m.message_id, m.sender_id, m.message_text, m.message_type,
                       m.file_path, m.file_name, m.sent_at,
                       u.full_name AS sender_name, ur.role_name AS sender_role
                FROM chat_messages m
                JOIN users u     ON m.sender_id = u.user_id
                JOIN user_roles ur ON u.role_id = ur.role_id
                WHERE m.conversation_id = ? AND m.is_deleted = 0
                  AND m.message_id < ?
                ORDER BY m.message_id DESC LIMIT 30
            ";
            $stmt = $conn->prepare($sql);
            $stmt->bind_param("ii", $conv_id, $before_id);
        } elseif ($after_id > 0) {
            // Polling: only new messages
            $sql = "
                SELECT m.message_id, m.sender_id, m.message_text, m.message_type,
                       m.file_path, m.file_name, m.sent_at,
                       u.full_name AS sender_name, ur.role_name AS sender_role
                FROM chat_messages m
                JOIN users u     ON m.sender_id = u.user_id
                JOIN user_roles ur ON u.role_id = ur.role_id
                WHERE m.conversation_id = ? AND m.is_deleted = 0
                  AND m.message_id > ?
                ORDER BY m.message_id ASC LIMIT 50
            ";
            $stmt = $conn->prepare($sql);
            $stmt->bind_param("ii", $conv_id, $after_id);
        } else {
            // Initial load: last 50 messages
            $sql = "
                SELECT m.message_id, m.sender_id, m.message_text, m.message_type,
                       m.file_path, m.file_name, m.sent_at,
                       u.full_name AS sender_name, ur.role_name AS sender_role
                FROM chat_messages m
                JOIN users u     ON m.sender_id = u.user_id
                JOIN user_roles ur ON u.role_id = ur.role_id
                WHERE m.conversation_id = ? AND m.is_deleted = 0
                ORDER BY m.message_id DESC LIMIT 50
            ";
            $stmt = $conn->prepare($sql);
            $stmt->bind_param("i", $conv_id);
        }

        $stmt->execute();
        $msgs = $stmt->get_result()->fetch_all(MYSQLI_ASSOC);

        if (!$load_more && !$after_id) {
            $msgs = array_reverse($msgs); // show oldest first
        }

        // Mark as read
        $now = date('Y-m-d H:i:s');
        $mr  = $conn->prepare("UPDATE chat_participants SET last_read_at=? WHERE conversation_id=? AND user_id=?");
        $mr->bind_param("sii", $now, $conv_id, $me);
        $mr->execute();

        ob_end_clean();
        echo json_encode(['success' => true, 'messages' => $msgs, 'my_id' => $me]);
        break;

    // ─────────────────────────────────────────────────────────────────────────
    // SEND_MESSAGE
    // ─────────────────────────────────────────────────────────────────────────
    case 'send_message':
        $conv_id  = (int)($_POST['conversation_id'] ?? 0);
        $msg_text = trim($_POST['message_text'] ?? '');
        $msg_type = 'text';
        $file_path = null;
        $file_name = null;

        if (!$conv_id || (!$msg_text && empty($_FILES['file']['name']))) {
            echo json_encode(['success' => false, 'message' => 'Missing data.']);
            exit;
        }

        // Access check
        $ac = $conn->prepare("SELECT participant_id FROM chat_participants WHERE conversation_id=? AND user_id=?");
        $ac->bind_param("ii", $conv_id, $me);
        $ac->execute();
        if (!$ac->get_result()->fetch_assoc()) {
            echo json_encode(['success' => false, 'message' => 'Not a participant.']);
            exit;
        }

        // Handle file upload
        if (!empty($_FILES['file']['name']) && $_FILES['file']['error'] === UPLOAD_ERR_OK) {
            $allowed_types = ['image/jpeg','image/png','image/gif','application/pdf',
                              'application/msword','application/vnd.openxmlformats-officedocument.wordprocessingml.document'];
            $ftype = mime_content_type($_FILES['file']['tmp_name']);
            if (!in_array($ftype, $allowed_types)) {
                echo json_encode(['success' => false, 'message' => 'File type not allowed.']);
                exit;
            }
            $upload_dir = dirname(__DIR__) . '/chat_files/';
            if (!is_dir($upload_dir)) mkdir($upload_dir, 0755, true);
            $safe_name  = preg_replace('/[^a-zA-Z0-9._-]/', '_', $_FILES['file']['name']);
            $final_name = date('YmdHis') . '_' . $safe_name;
            move_uploaded_file($_FILES['file']['tmp_name'], $upload_dir . $final_name);
            $file_path  = 'chat_files/' . $final_name;
            $file_name  = $_FILES['file']['name'];
            $msg_type   = str_starts_with($ftype, 'image/') ? 'image' : 'file';
            if (!$msg_text) $msg_text = "Sent a file: {$_FILES['file']['name']}";
        }

        $conn->begin_transaction();
        try {
            $ins = $conn->prepare("
                INSERT INTO chat_messages (conversation_id, sender_id, message_text, message_type, file_path, file_name)
                VALUES (?, ?, ?, ?, ?, ?)
            ");
            $ins->bind_param("iissss", $conv_id, $me, $msg_text, $msg_type, $file_path, $file_name);
            $ins->execute();
            $msg_id = $conn->insert_id;

            // Update last_message_at on the conversation
            $now = date('Y-m-d H:i:s');
            $upd = $conn->prepare("UPDATE chat_conversations SET last_message_at=? WHERE conversation_id=?");
            $upd->bind_param("si", $now, $conv_id);
            $upd->execute();

            $conn->commit();
            ob_end_clean();
            echo json_encode(['success' => true, 'message_id' => $msg_id]);
        } catch (\Throwable $e) {
            $conn->rollback();
            ob_end_clean();
            echo json_encode(['success' => false, 'message' => 'DB error: ' . $e->getMessage()]);
        }
        break;

    // ─────────────────────────────────────────────────────────────────────────
    // START_CONVERSATION: create direct or group chat
    // ─────────────────────────────────────────────────────────────────────────
    case 'start_conversation':
        $type      = $_POST['type'] ?? 'direct'; // direct | group
        $title     = trim($_POST['title'] ?? '');
        $user_ids  = json_decode($_POST['user_ids'] ?? '[]', true); // array of user_ids to add

        if (empty($user_ids) || !is_array($user_ids)) {
            echo json_encode(['success' => false, 'message' => 'No participants selected.']);
            exit;
        }

        // For direct chat: check if a direct conversation already exists with this user
        if ($type === 'direct' && count($user_ids) === 1) {
            $other = (int)$user_ids[0];
            $existing_sql = "
                SELECT c.conversation_id FROM chat_conversations c
                JOIN chat_participants p1 ON c.conversation_id = p1.conversation_id AND p1.user_id = ?
                JOIN chat_participants p2 ON c.conversation_id = p2.conversation_id AND p2.user_id = ?
                WHERE c.conversation_type = 'direct' AND c.is_active = 1
                LIMIT 1
            ";
            $ex = $conn->prepare($existing_sql);
            $ex->bind_param("ii", $me, $other);
            $ex->execute();
            $ex_row = $ex->get_result()->fetch_assoc();
            if ($ex_row) {
                echo json_encode(['success' => true, 'conversation_id' => $ex_row['conversation_id'], 'existing' => true]);
                exit;
            }
        }

        $conn->begin_transaction();
        try {
            // Create conversation
            $ins_conv = $conn->prepare("
                INSERT INTO chat_conversations (conversation_type, title, created_by)
                VALUES (?, ?, ?)
            ");
            $ins_conv->bind_param("ssi", $type, $title, $me);
            $ins_conv->execute();
            $conv_id = $conn->insert_id;

            // Add creator
            $ins_part = $conn->prepare("INSERT INTO chat_participants (conversation_id, user_id) VALUES (?,?)");
            $ins_part->bind_param("ii", $conv_id, $me);
            $ins_part->execute();

            // Add other participants
            foreach ($user_ids as $uid) {
                $uid = (int)$uid;
                if ($uid === $me) continue;
                $ins_part->bind_param("ii", $conv_id, $uid);
                $ins_part->execute();
            }

            $conn->commit();
            ob_end_clean();
            echo json_encode(['success' => true, 'conversation_id' => $conv_id]);
        } catch (\Throwable $e) {
            $conn->rollback();
            ob_end_clean();
            echo json_encode(['success' => false, 'message' => 'Error: ' . $e->getMessage()]);
        }
        break;

    // ─────────────────────────────────────────────────────────────────────────
    // GET_USERS: search system users to start a conversation with
    // ─────────────────────────────────────────────────────────────────────────
    case 'get_users':
        $raw = trim($_POST['q'] ?? '');
        $q   = '%' . $raw . '%';

        // Check if is_active column exists — fall back gracefully if not
        $col_check = $conn->query("SHOW COLUMNS FROM users LIKE 'is_active'");
        $active_clause = ($col_check && $col_check->num_rows > 0)
            ? 'AND u.is_active = 1'
            : '';

        // Exclude patient-type roles — only return staff
        $sql = "SELECT u.user_id, u.full_name, ur.role_name
                FROM users u
                JOIN user_roles ur ON u.role_id = ur.role_id
                WHERE u.user_id <> ?
                  {$active_clause}
                  AND UPPER(ur.role_code) NOT IN ('PATIENT','PAT','PATIENT_PORTAL')
                  AND UPPER(ur.role_name) NOT LIKE '%PATIENT%'
                  AND (u.full_name LIKE ? OR ur.role_name LIKE ?)
                ORDER BY ur.role_name ASC, u.full_name ASC
                LIMIT 100";

        $stmt = $conn->prepare($sql);
        if (!$stmt) {
            ob_end_clean();
            echo json_encode(['success' => false, 'message' => 'Query prepare failed: ' . $conn->error]);
            exit;
        }
        $stmt->bind_param("iss", $me, $q, $q);
        $stmt->execute();
        $users = $stmt->get_result()->fetch_all(MYSQLI_ASSOC);
        ob_end_clean();
        echo json_encode(['success' => true, 'users' => $users]);
        break;

    // ─────────────────────────────────────────────────────────────────────────
    // GET_UNREAD_COUNT: for the floating badge
    // ─────────────────────────────────────────────────────────────────────────
    case 'get_unread_count':
        $sql = "
            SELECT COALESCE(SUM(
                (SELECT COUNT(*) FROM chat_messages m
                 WHERE m.conversation_id = cp.conversation_id
                   AND m.sender_id <> ?
                   AND m.is_deleted = 0
                   AND m.sent_at > COALESCE(cp.last_read_at, '1970-01-01'))
            ), 0) AS total_unread
            FROM chat_participants cp WHERE cp.user_id = ?
        ";
        $stmt = $conn->prepare($sql);
        $stmt->bind_param("ii", $me, $me);
        $stmt->execute();
        $row = $stmt->get_result()->fetch_assoc();
        ob_end_clean();
        echo json_encode(['success' => true, 'unread' => (int)$row['total_unread']]);
        break;

    // ─────────────────────────────────────────────────────────────────────────
    // DELETE_MESSAGE (soft delete, own messages only)
    // ─────────────────────────────────────────────────────────────────────────
    case 'delete_message':
        $msg_id = (int)($_POST['message_id'] ?? 0);
        $stmt   = $conn->prepare("UPDATE chat_messages SET is_deleted=1 WHERE message_id=? AND sender_id=?");
        $stmt->bind_param("ii", $msg_id, $me);
        $stmt->execute();
        ob_end_clean();
        echo json_encode(['success' => $stmt->affected_rows > 0]);
        break;

    default:
        ob_end_clean();
        echo json_encode(['success' => false, 'message' => 'Unknown action.']);
}

} catch (\Throwable $e) {
    // Safety net — catch ANY fatal error and return valid JSON
    ob_end_clean();
    echo json_encode(['success' => false, 'message' => 'Server error: ' . $e->getMessage()]);
}