<?php
/**
 * SendInbox — официальный PHP SDK (REST API v1).
 * Требуется PHP 7.4+ с расширением cURL. Ключ: кабинет → Настройки → API-ключи.
 *
 *   require __DIR__ . "/sendinbox.php";
 *
 *   $si = new SendInbox\Client("sk_live_ВАШ_КЛЮЧ");
 *   $si->emails->send([
 *     "to" => "user@mail.ru", "subject" => "Привет",
 *     "html" => "<b>Тест из SDK</b>", "fromEmail" => "news@ваш-домен.ru",
 *   ]);
 *
 * Все методы возвращают ассоциативный массив (распарсенный JSON) и бросают
 * SendInbox\ApiException при HTTP-ошибке (в ней доступны $status и $body).
 */

namespace SendInbox;

class ApiException extends \Exception {
  /** @var int */ public $status;
  /** @var mixed */ public $body;
  public function __construct($message, $status = 0, $body = null) {
    parent::__construct($message);
    $this->status = $status;
    $this->body = $body;
  }
}

/** Ресурс с полным CRUD (списки, сегменты, подписчики). */
class Crud {
  private $c; private $base;
  public function __construct(Client $c, $base) { $this->c = $c; $this->base = $base; }
  public function list(array $params = []) { return $this->c->request("GET", $this->base . Client::qs($params)); }
  public function create(array $data) { return $this->c->request("POST", $this->base, $data); }
  public function get($id) { return $this->c->request("GET", $this->base . "/" . rawurlencode($id)); }
  public function update($id, array $data) { return $this->c->request("PATCH", $this->base . "/" . rawurlencode($id), $data); }
  public function remove($id) { return $this->c->request("DELETE", $this->base . "/" . rawurlencode($id)); }
}

class Emails {
  private $c; public function __construct(Client $c) { $this->c = $c; }
  public function send(array $payload) { return $this->c->request("POST", "/api/v1/emails", $payload); }
  public function get($id) { return $this->c->request("GET", "/api/v1/emails/" . rawurlencode($id)); }
  public function verify($email) { return $this->c->request("POST", "/api/v1/emails/info", ["email" => $email]); }
}

class Campaigns {
  private $c; public function __construct(Client $c) { $this->c = $c; }
  public function list() { return $this->c->request("GET", "/api/v1/campaigns"); }
  public function create(array $data) { return $this->c->request("POST", "/api/v1/campaigns", $data); }
  public function get($id) { return $this->c->request("GET", "/api/v1/campaigns/" . rawurlencode($id)); }
  public function send($id) { return $this->c->request("POST", "/api/v1/campaigns/" . rawurlencode($id) . "/send"); }
}

class Suppression {
  private $c; public function __construct(Client $c) { $this->c = $c; }
  public function list(array $params = []) { return $this->c->request("GET", "/api/v1/suppression" . Client::qs($params)); }
  public function add($email, $reason = null) { return $this->c->request("POST", "/api/v1/suppression", ["email" => $email, "reason" => $reason]); }
  public function remove($email) { return $this->c->request("DELETE", "/api/v1/suppression" . Client::qs(["email" => $email])); }
}

class Templates {
  private $c; public function __construct(Client $c) { $this->c = $c; }
  public function list() { return $this->c->request("GET", "/api/v1/templates"); }
  public function create(array $data) { return $this->c->request("POST", "/api/v1/templates", $data); }
}

class Automations {
  private $c; public function __construct(Client $c) { $this->c = $c; }
  public function trigger($event, $email, array $data = []) {
    return $this->c->request("POST", "/api/v1/automations/trigger", ["event" => $event, "email" => $email, "data" => (object) $data]);
  }
}

class Client {
  private $apiKey; private $baseUrl; private $timeout;
  /** @var Crud */ public $lists;
  /** @var Crud */ public $subscribers;
  /** @var Crud */ public $segments;
  /** @var Emails */ public $emails;
  /** @var Campaigns */ public $campaigns;
  /** @var Suppression */ public $suppression;
  /** @var Templates */ public $templates;
  /** @var Automations */ public $automations;

  public function __construct($apiKey, $baseUrl = "https://app.working-esender.ru", $timeout = 30) {
    if (!$apiKey) throw new ApiException("Не указан API-ключ");
    $this->apiKey = $apiKey;
    $this->baseUrl = rtrim($baseUrl, "/");
    $this->timeout = $timeout;
    $this->lists = new Crud($this, "/api/v1/lists");
    $this->subscribers = new Crud($this, "/api/v1/subscribers");
    $this->segments = new Crud($this, "/api/v1/segments");
    $this->emails = new Emails($this);
    $this->campaigns = new Campaigns($this);
    $this->suppression = new Suppression($this);
    $this->templates = new Templates($this);
    $this->automations = new Automations($this);
  }

  /** Агрегаты аккаунта за всё время. */
  public function stats() { return $this->request("GET", "/api/v1/stats"); }

  /** Собрать query-строку из массива (пустые значения пропускаются). */
  public static function qs(array $params) {
    $pairs = [];
    foreach ($params as $k => $v) {
      if ($v === null || $v === "") continue;
      $pairs[] = rawurlencode($k) . "=" . rawurlencode((string) $v);
    }
    return $pairs ? "?" . implode("&", $pairs) : "";
  }

  /** Низкоуровневый запрос. */
  public function request($method, $path, $body = null) {
    $ch = curl_init($this->baseUrl . $path);
    $headers = ["Authorization: Bearer " . $this->apiKey, "Accept: application/json"];
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout);
    if ($body !== null) {
      $headers[] = "Content-Type: application/json";
      curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body, JSON_UNESCAPED_UNICODE));
    }
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    $raw = curl_exec($ch);
    if ($raw === false) {
      $err = curl_error($ch);
      if (PHP_VERSION_ID < 80000) curl_close($ch); // с PHP 8.0 — no-op, с 8.5 — deprecated
      throw new ApiException("Сетевая ошибка: " . $err);
    }
    $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    if (PHP_VERSION_ID < 80000) curl_close($ch); // с PHP 8.0 — no-op, с 8.5 — deprecated
    $data = strlen($raw) ? json_decode($raw, true) : null;
    if ($status < 200 || $status >= 300) {
      $msg = (is_array($data) && isset($data["error"])) ? $data["error"] : ("HTTP " . $status);
      throw new ApiException($msg, $status, $data);
    }
    return $data;
  }
}
