<?php
/**
 * 5SIM API Wrapper
 * Docs: https://5sim.net/docs
 * Base URL: https://5sim.net/v1/
 *
 * Auth: Bearer token in Authorization header.
 * All requests: GET with Authorization + Accept: application/json
 */
class FiveSim {

    private string $token;
    private string $base_url;

    public function __construct(string $token, string $base_url = 'https://5sim.net/v1') {
        $this->token    = $token;
        $this->base_url = rtrim($base_url, '/');
    }

    // ── Core HTTP helper ─────────────────────────────────────────
    private function request(string $endpoint, bool $auth = true): array
    {
        $url     = $this->base_url . '/' . ltrim($endpoint, '/');
        $headers = ['Accept: application/json'];
        if ($auth) {
            $headers[] = 'Authorization: Bearer ' . $this->token;
        }

        $ch = curl_init();
        curl_setopt_array($ch, [
            CURLOPT_URL            => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT        => 30,
            CURLOPT_CONNECTTIMEOUT => 15,
            CURLOPT_SSL_VERIFYPEER => false,
            CURLOPT_SSL_VERIFYHOST => 0,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_USERAGENT      => 'FiveSim-PHP/1.0',
            CURLOPT_HTTPHEADER     => $headers,
        ]);

        $raw    = curl_exec($ch);
        $err    = curl_error($ch);
        $code   = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if ($err) {
            return ['success' => false, 'http_code' => 0, 'error' => 'cURL error: ' . $err];
        }
        if ($raw === false || $raw === '') {
            return ['success' => false, 'http_code' => $code, 'error' => 'Empty response'];
        }

        $data = json_decode($raw, true);
        if ($data === null) {
            // Some error responses are plain strings like "no free phones"
            $msg = trim($raw);
            return ['success' => false, 'http_code' => $code, 'error' => $msg ?: 'Invalid JSON'];
        }

        // 5SIM returns error details as a plain string in some cases
        if ($code >= 400) {
            $msg = is_string($data) ? $data : ($data['message'] ?? $data['error'] ?? $raw);
            return ['success' => false, 'http_code' => $code, 'error' => $msg];
        }

        return ['success' => true, 'http_code' => $code, 'data' => $data];
    }

    // ── 1. Get user profile / balance ────────────────────────────
    // GET /v1/user/profile
    // Response: {"id":1,"email":"...","balance":100,"rating":96,...}
    public function getProfile(): array
    {
        return $this->request('user/profile');
    }

    // ── 2. Get countries list (guest, no auth needed) ────────────
    // GET /v1/guest/countries
    // Response: {"england":{"iso":{"gb":1},"text_en":"England",...},...}
    public function getCountries(): array
    {
        return $this->request('guest/countries', false);
    }

    // ── 3. Get products + prices for a country+operator ──────────
    // GET /v1/guest/products/{country}/{operator}
    // operator = "any" for all operators
    // Response: {"facebook":{"Category":"activation","Qty":133,"Price":21},...}
    public function getProducts(string $country, string $operator = 'any'): array
    {
        return $this->request(
            'guest/products/' . rawurlencode($country) . '/' . rawurlencode($operator),
            false
        );
    }

    // ── 4. Get prices (optionally filtered by country/product) ───
    // GET /v1/guest/prices[?country=X&product=Y]
    // Response: {"england":{"facebook":{"vodafone":{"cost":4,"count":1260,"rate":99.99},...},...},...}
    public function getPrices(string $country = '', string $product = ''): array
    {
        $qs = [];
        if ($country !== '') $qs[] = 'country=' . rawurlencode($country);
        if ($product !== '') $qs[] = 'product=' . rawurlencode($product);
        $endpoint = 'guest/prices' . ($qs ? '?' . implode('&', $qs) : '');
        return $this->request($endpoint, false);
    }

    // ── 5. Buy activation number ─────────────────────────────────
    // GET /v1/user/buy/activation/{country}/{operator}/{product}
    // Response: {"id":11631253,"phone":"+447350690992","operator":"vodafone",
    //            "product":"facebook","price":21,"status":"PENDING","expires":"...","country":"england"}
    public function buyNumber(string $country, string $product, string $operator = 'any'): array
    {
        return $this->request(
            'user/buy/activation/' . rawurlencode($country) . '/' . rawurlencode($operator) . '/' . rawurlencode($product)
        );
    }

    // ── 6. Check order / get SMS ──────────────────────────────────
    // GET /v1/user/check/{id}
    // Response: {"id":...,"phone":"...","status":"RECEIVED","sms":[{"text":"...","code":"12345"}],...}
    public function checkOrder(int $order_id): array
    {
        return $this->request('user/check/' . $order_id);
    }

    // ── 7. Finish order (mark complete) ──────────────────────────
    // GET /v1/user/finish/{id}
    public function finishOrder(int $order_id): array
    {
        return $this->request('user/finish/' . $order_id);
    }

    // ── 8. Cancel order (refund if no SMS received) ───────────────
    // GET /v1/user/cancel/{id}
    public function cancelOrder(int $order_id): array
    {
        return $this->request('user/cancel/' . $order_id);
    }

    // ── 9. Ban order (bad number) ─────────────────────────────────
    // GET /v1/user/ban/{id}
    public function banOrder(int $order_id): array
    {
        return $this->request('user/ban/' . $order_id);
    }
}
