<?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 | JSON_UNESCAPED_UNICODE);
  exit;
}

function jsonBody(): array {
  $raw = file_get_contents('php://input');
  $data = json_decode($raw ?: '', true);
  if (!is_array($data)) respond(400, ['ok' => false, 'error' => 'Invalid JSON body']);
  return $data;
}

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

function getUserId(): int {
  $uid = (int)($_SESSION['user_id'] ?? 0);
  if ($uid <= 0) $uid = (int)($_SESSION['SESS_MEMBER_ID'] ?? 0);
  return $uid;
}

function getHeader(string $name): string {
  // Works across Apache/Nginx/FPM
  $key = 'HTTP_' . strtoupper(str_replace('-', '_', $name));
  $v = $_SERVER[$key] ?? '';
  if ($v !== '') return (string)$v;

  // Fallback if available
  if (function_exists('getallheaders')) {
    $h = getallheaders();
    foreach ($h as $k => $val) {
      if (strcasecmp($k, $name) === 0) return (string)$val;
    }
  }
  return '';
}

/**
 * Internal token auth (server-to-server).
 * If provided and matches, we allow the request even without browser cookies/session.
 */
function isInternalAuthorized(): bool {
  $sent = trim(getHeader('X-Internal-Token'));
  if ($sent === '') return false;

  // ✅ Prefer ENV token
  $expected = (string)(getenv('SUPPORT_INTERNAL_TOKEN') ?: '');

  // OPTIONAL: If you want to hardcode temporarily, uncomment:
  // $expected = 'PUT_YOUR_INTERNAL_TOKEN_HERE';

  if ($expected === '') return false;
  return hash_equals($expected, $sent);
}

require_once __DIR__ . '/../conn.php';
require_once __DIR__ . '/../config/pusher.php';

// Start session for browser-based auth paths
session_name(pickSessionName());
session_start();

$userId = getUserId();
$data = jsonBody();

$conversationId = (string)($data['conversationId'] ?? '');
$reason = trim((string)($data['reason'] ?? 'Requested live agent'));

if ($conversationId === '' || !ctype_digit($conversationId)) {
  respond(400, ['ok' => false, 'error' => 'conversationId is required']);
}

$internalAuthed = isInternalAuthorized();

try {
  $db->beginTransaction();

  $convStmt = $db->prepare("SELECT * FROM pth_support_conversations WHERE id = :cid LIMIT 1");
  $convStmt->execute([':cid' => (int)$conversationId]);
  $conv = $convStmt->fetch(PDO::FETCH_ASSOC);

  if (!$conv) {
    $db->rollBack();
    respond(404, ['ok' => false, 'error' => 'Conversation not found']);
  }

  $cid = (string)$conv['id'];
  $visitorId = (int)($conv['visitor_id'] ?? 0);

  // ======================
  // Authorization rules
  // ======================
  $allowed = false;

  // ✅ Server-to-server (bot/backend)
  if ($internalAuthed) {
    $allowed = true;
  }

  // ✅ Browser-based / session-based (existing behavior)
  if (!$allowed) {
    if (!empty($_SESSION['support_conversations'][$cid])) $allowed = true;
    if ($userId > 0 && $visitorId > 0 && $userId === $visitorId) $allowed = true;
    if (!empty($_COOKIE['PHPSESSADM']) && $userId > 0) $allowed = true; // admin can request too
  }

  if (!$allowed) {
    $db->rollBack();
    respond(403, [
      'ok' => false,
      'error' => 'Not allowed',
      // helpful debug (safe)
      'debug' => [
        'internalAuthed' => $internalAuthed,
        'userId' => $userId,
        'visitorId' => $visitorId,
        'hasSessionFlag' => !empty($_SESSION['support_conversations'][$cid]),
        'hasAdminCookie' => !empty($_COOKIE['PHPSESSADM']),
      ],
    ]);
  }

  // If already with agent, keep as is
  $currentState = (string)($conv['state'] ?? 'BOT');
  if ($currentState !== 'AGENT' && $currentState !== 'CLOSED') {
    $upd = $db->prepare("UPDATE pth_support_conversations SET state='HANDOFF_PENDING', updated_at=NOW() WHERE id=:cid");
    $upd->execute([':cid' => (int)$conversationId]);
  }

  // Upsert queue row
  $requestedBy = null;
  if ($visitorId > 0) $requestedBy = $visitorId;
  else if ($userId > 0) $requestedBy = $userId;

  $q = $db->prepare("
    INSERT INTO pth_support_queue (conversation_id, status, requested_by, requested_at)
    VALUES (:cid, 'WAITING', :rb, NOW())
    ON DUPLICATE KEY UPDATE
      status='WAITING',
      requested_by=VALUES(requested_by),
      requested_at=NOW(),
      accepted_by=NULL,
      accepted_at=NULL
  ");
  $q->execute([
    ':cid' => (int)$conversationId,
    ':rb'  => $requestedBy,
  ]);

  $db->commit();

} catch (Throwable $e) {
  if (isset($db) && $db->inTransaction()) $db->rollBack();
  respond(500, ['ok' => false, 'error' => 'Failed to request handoff', 'message' => $e->getMessage()]);
}

/** Broadcast */
$pusher = pusher_instance();

// notify the user chat
$pusher->trigger("private-support.$conversationId", "handoff.requested", [
  'conversationId' => (string)$conversationId,
  'reason' => $reason,
  'ts' => date('c'),
]);

// notify agents queue (agent dashboard subscribes here)
$pusher->trigger("private-support-queue", "handoff.requested", [
  'conversationId' => (string)$conversationId,
  'reason' => $reason,
  'ts' => date('c'),
]);

respond(200, [
  'ok' => true,
  'status' => 'HANDOFF_PENDING',
  'conversationId' => (string)$conversationId,
]);
