<?php
/**
 * SMS Portal REST API v1
 * Authentication: X-API-Key header
 */
require_once dirname(__DIR__, 2) . '/functions.php';
require_once dirname(__DIR__, 2) . '/providers/router.php';

header('Content-Type: application/json');
header('Access-Control-Allow-Origin: https://papsms.com');
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header('Access-Control-Allow-Headers: X-API-Key, Content-Type');

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(204); exit; }

function apiError(string $msg, int $code = 400): never {
    http_response_code($code);
    echo json_encode(['success'=>false,'error'=>$msg]);
    exit;
}
function apiOk(array $data): never {
    echo json_encode(array_merge(['success'=>true], $data));
    exit;
}

// Rate limiting for API
$clientIp = $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
if (!checkRateLimit('api', $clientIp, 120, 60)) {
    apiError('Rate limit exceeded. Max 120 requests per minute.', 429);
}
recordRateLimit('api', $clientIp);

// Authenticate
$apiKey = $_SERVER['HTTP_X_API_KEY'] ?? $_GET['api_key'] ?? '';
if (!$apiKey) apiError('API key required', 401);
if (strlen($apiKey) > 128) apiError('Invalid API key', 401);

$db   = getDB();
$stmt = $db->prepare("SELECT * FROM users WHERE api_key=? AND is_active=1");
$stmt->execute([$apiKey]);
$user = $stmt->fetch();
if (!$user) apiError('Invalid or inactive API key', 401);

// Route
$path   = trim($_SERVER['PATH_INFO'] ?? '', '/');
$method = $_SERVER['REQUEST_METHOD'];

// Sanitize path
$path = preg_replace('/[^a-z0-9\-\/]/', '', $path);

// Parse JSON body
$body = [];
if ($method === 'POST') {
    $raw = file_get_contents('php://input');
    if (strlen($raw) > 65536) apiError('Request too large', 413);
    $body = json_decode($raw, true) ?? $_POST;
}

// ── GET /balance ───────────────────────────────────────────────────────
if ($path === 'balance' && $method === 'GET') {
    apiOk(['balance' => (float)$user['balance'], 'currency' => getSetting('site_currency','USD')]);
}

// ── GET /services ──────────────────────────────────────────────────────
if ($path === 'services' && $method === 'GET') {
    $rows = $db->query("SELECT id,code,name,icon FROM services WHERE is_active=1 ORDER BY sort_order ASC")->fetchAll();
    apiOk(['services' => $rows]);
}

// ── GET /countries ─────────────────────────────────────────────────────
if ($path === 'countries' && $method === 'GET') {
    $serviceCode = substr(trim($_GET['service'] ?? ''), 0, 20);
    if ($serviceCode) {
        $svcStmt = $db->prepare("SELECT id FROM services WHERE code=?");
        $svcStmt->execute([$serviceCode]);
        $svc = $svcStmt->fetch();
        if (!$svc) apiError('Service not found');
        $cStmt = $db->prepare("
            SELECT c.id, c.code, c.name, c.flag, MIN(pr.price) AS min_price, SUM(pr.stock) AS total_stock
            FROM prices pr
            JOIN countries c ON c.id=pr.country_id
            JOIN providers pv ON pv.id=pr.provider_id
            WHERE pr.service_id=? AND pr.stock>0 AND pv.is_active=1
            GROUP BY c.id
            ORDER BY c.name ASC
        ");
        $cStmt->execute([$svc['id']]);
        $rows = $cStmt->fetchAll();
    } else {
        $rows = $db->query("SELECT id,code,name,flag FROM countries WHERE is_active=1 ORDER BY name ASC")->fetchAll();
    }
    apiOk(['countries' => $rows]);
}

// ── POST /buy ──────────────────────────────────────────────────────────
if ($path === 'buy' && $method === 'POST') {
    $serviceCode  = substr(trim($body['service'] ?? ''), 0, 20);
    $countryCode  = substr(trim($body['country'] ?? ''), 0, 10);
    $providerSlug = isset($body['provider']) ? substr(trim($body['provider']), 0, 30) : null;

    $svcStmt = $db->prepare("SELECT * FROM services WHERE code=? AND is_active=1");
    $svcStmt->execute([$serviceCode]);
    $svc = $svcStmt->fetch();
    if (!$svc) apiError('Service not found or inactive');

    $ctrStmt = $db->prepare("SELECT * FROM countries WHERE code=? AND is_active=1");
    $ctrStmt->execute([strtoupper($countryCode)]);
    $ctr = $ctrStmt->fetch();
    if (!$ctr && is_numeric($countryCode)) {
        $ctrStmt2 = $db->prepare("SELECT * FROM countries WHERE id=? AND is_active=1");
        $ctrStmt2->execute([(int)$countryCode]);
        $ctr = $ctrStmt2->fetch();
    }
    if (!$ctr) apiError('Country not found');

    if ($providerSlug) {
        $provStmt = $db->prepare("SELECT * FROM providers WHERE slug=? AND is_active=1");
        $provStmt->execute([$providerSlug]);
        $provRow = $provStmt->fetch();
    } else {
        $provStmt = $db->prepare("
            SELECT p.* FROM providers p
            JOIN prices pr ON pr.provider_id=p.id
            WHERE pr.service_id=? AND pr.country_id=? AND pr.stock>0 AND p.is_active=1
            ORDER BY pr.price ASC LIMIT 1
        ");
        $provStmt->execute([$svc['id'], $ctr['id']]);
        $provRow = $provStmt->fetch();
    }
    if (!$provRow) apiError('No provider available for this combination');

    $prStmt = $db->prepare("SELECT price FROM prices WHERE service_id=? AND country_id=? AND provider_id=?");
    $prStmt->execute([$svc['id'], $ctr['id'], $provRow['id']]);
    $priceRow = $prStmt->fetch();
    $price = $priceRow ? (float)$priceRow['price'] : 0.10;

    if ((float)$user['balance'] < $price) {
        apiError('Insufficient balance');
    }

    $provider = ProviderRouter::get($provRow['slug']);
    if (!$provider) apiError('Provider connection failed');

    $result = $provider->getNumber($ctr['code'], $svc['code']);
    if (!$result['success']) apiError($result['error']);

    $db->prepare("UPDATE users SET balance=balance-? WHERE id=?")->execute([$price, $user['id']]);
    $expires = time() + (ACTIVATION_TIMEOUT * 60);
    $db->prepare("INSERT INTO activations (user_id,service_id,country_id,provider_id,provider_activation_id,phone_number,price,status,expires_at) VALUES (?,?,?,?,?,?,?,'pending',?)")
       ->execute([$user['id'], $svc['id'], $ctr['id'], $provRow['id'], $result['id'], $result['number'], $price, $expires]);
    $actId = $db->lastInsertId();

    apiOk([
        'activation_id' => $actId,
        'phone_number'  => $result['number'],
        'service'       => $svc['code'],
        'country'       => $ctr['code'],
        'price'         => $price,
        'expires_at'    => $expires,
    ]);
}

// ── GET /status/{id} ───────────────────────────────────────────────────
if (preg_match('#^status/(\d+)$#', $path, $m) && $method === 'GET') {
    $actId = (int)$m[1];
    $actStmt = $db->prepare("SELECT a.*, p.slug AS provider_slug FROM activations a JOIN providers p ON p.id=a.provider_id WHERE a.id=? AND a.user_id=?");
    $actStmt->execute([$actId, $user['id']]);
    $row = $actStmt->fetch();
    if (!$row) apiError('Activation not found', 404);

    if ($row['status'] === 'received') {
        apiOk(['status'=>'received','code'=>$row['sms_code'],'full_text'=>$row['sms_text']]);
    }
    if (time() > $row['expires_at']) {
        $db->prepare("UPDATE activations SET status='expired',updated_at=? WHERE id=?")->execute([time(),$actId]);
        apiOk(['status'=>'expired','code'=>null]);
    }

    $provider = ProviderRouter::get($row['provider_slug']);
    if (!$provider) apiError('Provider unavailable');

    $sms = $provider->getMessage($row['provider_activation_id']);
    if ($sms['received']) {
        $db->prepare("UPDATE activations SET sms_code=?,sms_text=?,status='received',updated_at=? WHERE id=?")
           ->execute([$sms['code'], $sms['full_text'], time(), $actId]);
        apiOk(['status'=>'received','code'=>$sms['code'],'full_text'=>$sms['full_text']]);
    }
    apiOk(['status'=>'pending','code'=>null]);
}

// ── POST /cancel/{id} ─────────────────────────────────────────────────
if (preg_match('#^cancel/(\d+)$#', $path, $m) && $method === 'POST') {
    $actId = (int)$m[1];
    $actStmt = $db->prepare("SELECT a.*, p.slug AS provider_slug FROM activations a JOIN providers p ON p.id=a.provider_id WHERE a.id=? AND a.user_id=? AND a.status='pending'");
    $actStmt->execute([$actId, $user['id']]);
    $row = $actStmt->fetch();
    if (!$row) apiError('Cannot cancel this activation', 400);

    $provider  = ProviderRouter::get($row['provider_slug']);
    $cancelled = $provider ? $provider->cancelNumber($row['provider_activation_id']) : true;

    if ($cancelled) {
        $db->prepare("UPDATE activations SET status='cancelled',updated_at=? WHERE id=?")->execute([time(),$actId]);
        $db->prepare("UPDATE users SET balance=balance+? WHERE id=?")->execute([$row['price'], $user['id']]);
        apiOk(['refunded' => $row['price']]);
    }
    apiError('Cancel failed on provider side');
}

// ── Batch Buy ────────────────────────────────────────────────────────────
if ($path === 'batch-buy' && $method === 'POST') {
    $orders = $body['orders'] ?? [];
    if (empty($orders) || !is_array($orders)) apiError('orders array required');
    if (count($orders) > 20) apiError('Maximum 20 orders per batch');

    $validated = [];
    $totalCost = 0;
    foreach ($orders as $i => $order) {
        $sc = substr(trim($order['service'] ?? ''), 0, 20);
        $cc = strtoupper(substr(trim($order['country'] ?? ''), 0, 10));
        $qty = min(max((int)($order['quantity'] ?? 1), 1), 10);

        $svcStmt = $db->prepare("SELECT * FROM services WHERE code=? AND is_active=1");
        $svcStmt->execute([$sc]);
        $svc = $svcStmt->fetch();
        if (!$svc) apiError("Order #$i: service not found");

        $ctrStmt = $db->prepare("SELECT * FROM countries WHERE code=? AND is_active=1");
        $ctrStmt->execute([$cc]);
        $ctr = $ctrStmt->fetch();
        if (!$ctr) apiError("Order #$i: country not found");

        $provStmt = $db->prepare("
            SELECT p.* FROM providers p
            JOIN prices pr ON pr.provider_id=p.id
            WHERE pr.service_id=? AND pr.country_id=? AND pr.stock>0 AND p.is_active=1
            ORDER BY pr.price ASC LIMIT 1
        ");
        $provStmt->execute([$svc['id'], $ctr['id']]);
        $provRow = $provStmt->fetch();
        if (!$provRow) apiError("Order #$i: no provider available");

        $prStmt = $db->prepare("SELECT price FROM prices WHERE service_id=? AND country_id=? AND provider_id=?");
        $prStmt->execute([$svc['id'], $ctr['id'], $provRow['id']]);
        $prRow = $prStmt->fetch();
        $price = $prRow ? (float)$prRow['price'] : 0.10;

        $totalCost += $price * $qty;
        $validated[] = compact('svc','ctr','provRow','price','qty');
    }

    if ((float)$user['balance'] < $totalCost) {
        apiError('Insufficient balance. Need $'.number_format($totalCost,4));
    }

    $results = [];
    $totalDeducted = 0;
    foreach ($validated as $item) {
        for ($q = 0; $q < $item['qty']; $q++) {
            $provider = ProviderRouter::get($item['provRow']['slug']);
            if (!$provider) {
                $results[] = ['success'=>false,'error'=>'Provider unavailable','service'=>$item['svc']['code'],'country'=>$item['ctr']['code']];
                continue;
            }
            $result = $provider->getNumber($item['ctr']['code'], $item['svc']['code']);
            if (!$result['success']) {
                $results[] = ['success'=>false,'error'=>$result['error'],'service'=>$item['svc']['code'],'country'=>$item['ctr']['code']];
                continue;
            }
            $db->prepare("UPDATE users SET balance=balance-? WHERE id=?")->execute([$item['price'], $user['id']]);
            $totalDeducted += $item['price'];
            $expires = time() + (ACTIVATION_TIMEOUT * 60);
            $db->prepare("INSERT INTO activations (user_id,service_id,country_id,provider_id,provider_activation_id,phone_number,price,status,expires_at) VALUES (?,?,?,?,?,?,?,'pending',?)")
               ->execute([$user['id'],$item['svc']['id'],$item['ctr']['id'],$item['provRow']['id'],$result['id'],$result['number'],$item['price'],$expires]);
            $actId = $db->lastInsertId();
            $results[] = ['success'=>true,'activation_id'=>$actId,'phone_number'=>$result['number'],'service'=>$item['svc']['code'],'country'=>$item['ctr']['code'],'price'=>$item['price'],'expires_at'=>$expires];
        }
    }

    $balStmt = $db->prepare("SELECT balance FROM users WHERE id=?");
    $balStmt->execute([$user['id']]);
    apiOk(['results'=>$results,'total_deducted'=>$totalDeducted,'remaining_balance'=>(float)$balStmt->fetchColumn()]);
}

apiError("Endpoint not found: $path", 404);
