<?php
declare(strict_types=1);

require_once __DIR__ . '/_cors.php';
header('Content-Type: application/json; charset=utf-8');

function respond(int $status, array $payload): void {
  http_response_code($status);
  echo json_encode($payload, JSON_UNESCAPED_SLASHES);
  exit;
}

function pickSessionName(): ?string {
  if (!empty($_COOKIE['PHPSESSADM'])) return 'PHPSESSADM';
  if (!empty($_COOKIE['PHPSESSCLI'])) return 'PHPSESSCLI';
  if (!empty($_COOKIE['PHPSESSAFF'])) return 'PHPSESSAFF';
  return null;
}

require_once __DIR__ . '/conn.php';

/** ---------- role helpers (adjust role strings to match your DB) ---------- */
function roleIs(array $user, array $roles): bool {
  $r = strtolower((string)($user['role'] ?? ''));
  foreach ($roles as $x) if ($r === strtolower($x)) return true;
  return false;
}
function isSuperAdmin(array $u): bool { return roleIs($u, ['super_admin','superadmin']); }
function isNational(array $u): bool { return roleIs($u, ['national','national_leader']); }
function isCounty(array $u): bool { return roleIs($u, ['county','county_rep']); }
function isConstituency(array $u): bool { return roleIs($u, ['constituency','constituency_rep']); }
function isWard(array $u): bool { return roleIs($u, ['ward','ward_rep']); }

/** ---------- session ---------- */
$sessionName = pickSessionName();
if (!$sessionName) respond(401, ['error' => 'Not authenticated (no session cookie)']);
session_name($sessionName);
session_start();

$userId = (int)($_SESSION['user_id'] ?? 0);
if ($userId <= 0) $userId = (int)($_SESSION['SESS_MEMBER_ID'] ?? 0);
if ($userId <= 0) respond(401, ['error' => 'Not authenticated']);

/** ---------- input ---------- */
$tab = strtolower(trim((string)($_GET['tab'] ?? 'all'))); // all|unread|archived
if (!in_array($tab, ['all','unread','archived'], true)) $tab = 'all';

/** ---------- load current user geo context ---------- */
$uStmt = $db->prepare("
  SELECT id, role, name, county_id, constituency_id, ward_id, polling_station_id
  FROM users
  WHERE id = :uid
  LIMIT 1
");
$uStmt->execute([':uid' => $userId]);
$user = $uStmt->fetch(PDO::FETCH_ASSOC);
if (!$user) respond(401, ['error' => 'User not found']);

$countyId = (int)($user['county_id'] ?? 0);
$constId  = (int)($user['constituency_id'] ?? 0);
$wardId   = (int)($user['ward_id'] ?? 0);
$psId     = (int)($user['polling_station_id'] ?? 0);

try {
  /**
   * IMPORTANT: This inbox supports BOTH:
   *  - membership rooms (dm/custom) via pth_party_room_members
   *  - scope rooms (polling_station/ward/constituency/county/national) via scope fields
   *
   * Performance notes:
   *  - Ensure pth_party_messages has INDEX(room_id, id)
   *  - Ensure pth_party_room_user_state has PK(room_id, user_id)
   */

  // 1) Build the room list available to this user
  //    - membership rooms (any room where user is in members)
  //    - plus scope rooms matching their geo
  //    - plus national rooms (policy: visible to everyone)
  $sqlRooms = "
    SELECT DISTINCT r.id AS roomId
    FROM pth_party_room r
    JOIN pth_party_room_members rm ON rm.room_id = r.id
    WHERE rm.user_id = :uid

    UNION DISTINCT
    SELECT r.id AS roomId
    FROM pth_party_room r
    WHERE r.scope_level = 'national'

    UNION DISTINCT
    SELECT r.id AS roomId
    FROM pth_party_room r
    WHERE r.scope_level = 'county' AND r.county_id = :county_id

    UNION DISTINCT
    SELECT r.id AS roomId
    FROM pth_party_room r
    WHERE r.scope_level = 'constituency' AND r.constituency_id = :const_id

    UNION DISTINCT
    SELECT r.id AS roomId
    FROM pth_party_room r
    WHERE r.scope_level = 'ward' AND r.ward_id = :ward_id

    UNION DISTINCT
    SELECT r.id AS roomId
    FROM pth_party_room r
    WHERE r.scope_level = 'polling_station' AND r.polling_station_id = :ps_id
  ";

  $stmtRooms = $db->prepare($sqlRooms);
  $stmtRooms->execute([
    ':uid' => $userId,
    ':county_id' => $countyId,
    ':const_id' => $constId,
    ':ward_id' => $wardId,
    ':ps_id' => $psId,
  ]);

  $roomIds = array_map(fn($r) => (int)$r['roomId'], $stmtRooms->fetchAll(PDO::FETCH_ASSOC));
  $roomIds = array_values(array_unique(array_filter($roomIds, fn($x) => $x > 0)));

  if (!$roomIds) {
    respond(200, [
      'counts' => ['all' => 0, 'unread' => 0, 'archived' => 0],
      'conversations' => [],
    ]);
  }

  $in = implode(',', array_fill(0, count($roomIds), '?'));

  /**
   * 2) Load room meta + last message + unread count + archive state
   *    NOTE: unread excludes my own messages.
   */
  $sql = "
    SELECT
      r.id AS roomId,
      r.room_key AS roomKey,
      r.room_name AS roomTitle,
      r.room_type AS roomType,
      r.scope_level AS scopeLevel,
      r.created_at AS roomCreatedAt,

      COALESCE(s.is_archived, 0) AS isArchived,
      COALESCE(s.last_read_message_id, 0) AS lastReadMessageId,

      lm.id AS lastMessageId,
      lm.body AS lastMessage,
      lm.created_at AS updatedAt,

      -- unread count (uses last_read_message_id)
      (
        SELECT COUNT(*)
        FROM pth_party_messages m
        WHERE m.room_id = r.id
          AND m.id > COALESCE(s.last_read_message_id, 0)
          AND m.user_id <> ?
          AND (m.is_deleted = 0 OR m.is_deleted IS NULL)
      ) AS unreadCount

    FROM pth_party_room r
    LEFT JOIN pth_party_room_user_state s
      ON s.room_id = r.id AND s.user_id = ?

    LEFT JOIN pth_party_messages lm
      ON lm.id = (
        SELECT id
        FROM pth_party_messages
        WHERE room_id = r.id
          AND (is_deleted = 0 OR is_deleted IS NULL)
        ORDER BY id DESC
        LIMIT 1
      )

    WHERE r.id IN ($in)
    ORDER BY COALESCE(lm.created_at, r.created_at) DESC
  ";

  $params = [];
  $params[] = $userId; // unread exclude
  $params[] = $userId; // state join
  foreach ($roomIds as $rid) $params[] = $rid;

  $stmt = $db->prepare($sql);
  $stmt->execute($params);
  $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

  /**
   * 3) For membership rooms only, compute participants list + DM other name
   *    We do it in separate query to avoid heavy GROUP_CONCAT joins on messages.
   */
  $sqlParts = "
    SELECT
      rm.room_id AS roomId,
      COUNT(*) AS memberCount,
      GROUP_CONCAT(u.name ORDER BY u.name SEPARATOR ', ') AS participantsCsv,
      MAX(CASE WHEN rm.user_id <> ? THEN u.name END) AS dmOtherName
    FROM pth_party_room_members rm
    JOIN users u ON u.id = rm.user_id
    WHERE rm.room_id IN ($in)
    GROUP BY rm.room_id
  ";

  $paramsParts = [];
  $paramsParts[] = $userId;
  foreach ($roomIds as $rid) $paramsParts[] = $rid;

  $stmtParts = $db->prepare($sqlParts);
  $stmtParts->execute($paramsParts);
  $partRows = $stmtParts->fetchAll(PDO::FETCH_ASSOC);

  $partsByRoom = [];
  foreach ($partRows as $pr) {
    $partsByRoom[(int)$pr['roomId']] = $pr;
  }

  // counts + filter by tab
  $all = 0; $unread = 0; $archived = 0;
  $conversations = [];

  foreach ($rows as $row) {
    $all++;

    $roomId = (int)$row['roomId'];
    $roomType = (string)$row['roomType'];
    $scopeLevel = (string)$row['scopeLevel'];

    $isArchived = ((int)$row['isArchived']) === 1;
    $unreadCount = (int)($row['unreadCount'] ?? 0);

    if ($isArchived) $archived++;
    if (!$isArchived && $unreadCount > 0) $unread++;

    // apply tab filter
    if ($tab === 'archived' && !$isArchived) continue;
    if ($tab === 'unread' && ($isArchived || $unreadCount <= 0)) continue;
    if ($tab === 'all' && $isArchived) continue;

    $participants = [];
    $memberCount = 0;
    $dmOtherName = '';

    // only membership rooms have participants
    if ($roomType === 'dm' || $scopeLevel === 'custom') {
      $pr = $partsByRoom[$roomId] ?? null;
      $memberCount = (int)($pr['memberCount'] ?? 0);

      $csv = trim((string)($pr['participantsCsv'] ?? ''));
      if ($csv !== '') $participants = array_values(array_filter(array_map('trim', explode(',', $csv))));

      $dmOtherName = trim((string)($pr['dmOtherName'] ?? ''));
    }

    // title rules
    $title = (string)$row['roomTitle'];
    if ($roomType === 'dm' && $dmOtherName !== '') {
      $title = $dmOtherName;
    }

    // fallback last message / updated time
    $lastMessage = $row['lastMessage'] ?? '—';
    $updatedAt = $row['updatedAt'] ?? $row['roomCreatedAt'];

    $conversations[] = [
      'roomId' => (string)$row['roomId'],
      'roomKey' => (string)$row['roomKey'],
      'roomType' => $roomType,
      'scopeLevel' => $scopeLevel,
      'title' => $title,

      'lastMessage' => $lastMessage,
      'updatedAt' => $updatedAt,

      'unreadCount' => $unreadCount,
      'unread' => (!$isArchived && $unreadCount > 0),

      'archived' => $isArchived,
      'participants' => $participants,
      'memberCount' => $memberCount,
    ];
  }

  respond(200, [
    'counts' => [
      'all' => $all,
      'unread' => $unread,
      'archived' => $archived,
    ],
    'conversations' => $conversations,
  ]);

} catch (Throwable $e) {
  respond(500, ['error' => 'inbox_failed', 'message' => $e->getMessage()]);
}
