<?php
/****************************************************
 * thirdparty/smsnotifications/zamtel.php
 * SMS helpers: billing, payments, vouchers + logging & cURL.
 *
 * ✅ UPDATE (YOUR REQUEST):
 *   - Use a SEPARATE sender id table (no settings table)
 *   - SenderId fetched from DB (gateway + tenant-aware optional)
 *   - Keep SMS_SENDER_ID constant as fallback
 *
 * ✅ TABLE EXAMPLE (recommended):
 *   sms_sender_ids
 *     - id (INT PK AI)
 *     - gateway (VARCHAR 20)   e.g. zamtel|airtel|mtn
 *     - sender_id (VARCHAR 50) e.g. Forward2026
 *     - tenant_code (VARCHAR 30) NULL allowed (optional)
 *     - is_active (TINYINT 1) default 1
 *     - created_at (DATETIME) optional
 *
 * ✅ Priority:
 *   1) tenant_code + gateway + is_active=1
 *   2) gateway + is_active=1 with tenant_code IS NULL/'' (global)
 *   3) SMS_SENDER_ID constant fallback
 ****************************************************/

// --------------------------------------------------
// CONFIG CONSTANTS (fallbacks)
// --------------------------------------------------
if (!defined('SMS_DEFAULT_GATEWAY')) {
    define('SMS_DEFAULT_GATEWAY', 'zamtel');       // zamtel|airtel|mtn
    define('SMS_SENDER_ID',       'Forward2026');  // fallback senderId (approved by gateway)
    define('ZAMTEL_API_KEY',      'ZTXd2G2ixsvLyAveXNnYghLle8EUOYQa');
    define('AIRTEL_API_KEY',      'REPLACE_ME');
    define('MTN_API_KEY',         'REPLACE_ME');

    // Short vs full link toggles
    define('SMS_USE_SHORT_LINK',  true);
    define('SMS_FORCE_REGEN',     false);
}

/* ---------- Payment link config ---------- */
if (!defined('PAY_ENDPOINT_PATH')) define('PAY_ENDPOINT_PATH', '/pay'); // e.g. /pay?ref=...
if (!defined('SHORT_PAY_PREFIX'))  define('SHORT_PAY_PREFIX',  '/p/');  // e.g. /p/{code}

/* ---------- Separate Sender ID table config ---------- */
if (!defined('SMS_SENDER_TABLE')) define('SMS_SENDER_TABLE', 'sms_sender_ids');

/* ---------- Tiny utils ---------- */

/** Logger → thirdparty/logs/sms.log */
function sms_debug_log(string $line): void {
    try {
        $dir = __DIR__ . '/../../logs';
        if (!is_dir($dir)) @mkdir($dir, 0775, true);
        $file  = $dir . '/sms.log';
        $stamp = date('Y-m-d H:i:s');
        @file_put_contents($file, "[$stamp] $line\n", FILE_APPEND);
    } catch (\Throwable $e) { /* no-op */ }
}

/** Zambia format helper -> returns 2609XXXXXXXX or null */
function sms_sanitize_msisdn(?string $raw): ?string {
    if (!$raw) return null;
    $digits = preg_replace('/\D+/', '', $raw);
    if ($digits === '') return null;

    if (preg_match('/^0(9\d{8})$/', $digits, $m)) return '260'.$m[1];
    if (preg_match('/^(9\d{8})$/', $digits, $m))  return '260'.$m[1];
    if (preg_match('/^2609\d{8}$/', $digits))     return $digits;

    return $digits; // fallback
}

/** Truncate to a safe SMS length */
function sms_truncate(string $msg, int $limit = 300): string {
    $msg = trim($msg);
    if (mb_strlen($msg, 'UTF-8') > $limit) {
        return mb_substr($msg, 0, $limit - 1, 'UTF-8') . '…';
    }
    return $msg;
}

/** Base URL helper */
function sms_base_url(): string {
    $env = getenv('PUBLIC_BASE_URL');
    if ($env && filter_var($env, FILTER_VALIDATE_URL)) {
        return rtrim($env, '/');
    }
    $scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') ? 'https' : 'http';
    $host   = $_SERVER['HTTP_HOST'] ?? 'smartsync.co.zm';
    return $scheme . '://' . $host;
}

/* ----------------- cURL GET helper ------------------- */
function http_simple_get(string $url): array {
    if (!function_exists('curl_init')) {
        $ctx = stream_context_create([
            'http' => [
                'method'  => 'GET',
                'timeout' => 15,
                'header'  => "Accept: application/json\r\n",
            ]
        ]);
        $body = @file_get_contents($url, false, $ctx);
        $status = 0;
        if (isset($http_response_header[0]) && preg_match('#\s(\d{3})\s#', $http_response_header[0], $m)) {
            $status = (int)$m[1];
        }
        return ['ok' => ($body !== false && $status === 200), 'status' => $status, 'body' => $body ?: null];
    }

    $ch = curl_init();
    curl_setopt_array($ch, [
        CURLOPT_URL            => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT        => 15,
        CURLOPT_HTTPHEADER     => ['Accept: application/json'],
        CURLOPT_SSL_VERIFYPEER => true,
        CURLOPT_SSL_VERIFYHOST => 2,
    ]);
    $body   = curl_exec($ch);
    $errno  = curl_errno($ch);
    $err    = curl_error($ch);
    $status = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    if ($errno) {
        sms_debug_log("HTTP GET error: $errno $err for $url");
        return ['ok'=>false, 'status'=>0, 'body'=>null, 'err'=>$err];
    }
    return ['ok'=>($status===200 && $body!==false), 'status'=>$status, 'body'=>$body];
}

/* ---------- Receipt link builders ---------- */

function build_downloader_link(string $tx_ref, bool $forceRegen = false): string {
    $base = sms_base_url();
    $q = 'receipt_' . $tx_ref . '.pdf';
    $url = $base . '/receiptDownloader.php?file=' . rawurlencode($q);
    if ($forceRegen) $url .= '&regen=1';
    return $url;
}

function build_short_link_for_txref(string $tx_ref, bool $forceRegen = false): string {
    $base = sms_base_url();
    $payload = $tx_ref . ($forceRegen ? '|1' : '|0');
    $code = rtrim(strtr(base64_encode($payload), '+/', '-_'), '=');
    return $base . '/r/' . $code;
}

/* ---------- Payment link builders ---------- */

function build_payment_link_for_bill(string $billNo, float $amount = 0.0, ?int $clientId = null): string {
    $base = sms_base_url();
    $q = ['ref' => $billNo];
    if ($amount > 0) $q['amt'] = number_format($amount, 2, '.', '');
    if (!empty($clientId)) $q['cid'] = (int)$clientId;
    return rtrim($base, '/') . PAY_ENDPOINT_PATH . '?' . http_build_query($q);
}

function build_short_payment_link(string $billNo, float $amount = 0.0, ?int $clientId = null): string {
    $base = sms_base_url();
    $payload = implode('|', [
        'BILL',
        $billNo,
        number_format(max(0.0, $amount), 2, '.', ''),
        $clientId ? (string)(int)$clientId : ''
    ]);
    $code = rtrim(strtr(base64_encode($payload), '+/', '-_'), '=');
    return rtrim($base, '/') . SHORT_PAY_PREFIX . $code;
}

// --------------------------------------------------
// DB: auto-connect optional (so this file can still run alone)
// --------------------------------------------------
function sms_try_get_db_connection(): ?mysqli
{
    try {
        $path = __DIR__ . '/../../assets/config/dbConnection.php';
        if (is_file($path)) {
            require_once $path;
            if (class_exists('DatabaseConnection')) {
                $db   = DatabaseConnection::getInstance();
                $conn = $db->getConnection();
                if ($conn instanceof mysqli) {
                    @$conn->set_charset('utf8mb4');
                    return $conn;
                }
            }
        }
    } catch (\Throwable $e) {
        sms_debug_log("sms_try_get_db_connection failed: " . $e->getMessage());
    }
    return null;
}

/**
 * ✅ Sender ID lookup from a separate table.
 *
 * Priority:
 *  1) tenant_code + gateway + is_active=1 (latest id)
 *  2) global (tenant_code is NULL or '') + gateway + is_active=1 (latest id)
 *  3) fallback SMS_SENDER_ID
 */
function sms_get_sender_id_from_table(?mysqli $conn, string $gateway = SMS_DEFAULT_GATEWAY, ?string $tenantCode = null): string
{
    $fallback = defined('SMS_SENDER_ID') ? (string)SMS_SENDER_ID : 'Forward2026';

    if (!$conn) $conn = sms_try_get_db_connection();
    if (!$conn) return $fallback;

    $gateway = strtolower(trim($gateway));
    $table   = SMS_SENDER_TABLE;

    // 1) Tenant-specific sender id
    if (!empty($tenantCode)) {
        try {
            $sql = "
                SELECT sender_id
                  FROM {$table}
                 WHERE is_active = 1
                   AND LOWER(gateway) = ?
                   AND tenant_code = ?
                 ORDER BY id DESC
                 LIMIT 1
            ";
            $st = $conn->prepare($sql);
            if ($st) {
                $st->bind_param('ss', $gateway, $tenantCode);
                $st->execute();
                $row = $st->get_result()->fetch_assoc();
                $st->close();
                if (!empty($row['sender_id'])) return (string)$row['sender_id'];
            }
        } catch (\Throwable $e) {
            sms_debug_log("Tenant senderId lookup error: " . $e->getMessage());
        }
    }

    // 2) Global sender id (no tenant_code)
    try {
        $sql = "
            SELECT sender_id
              FROM {$table}
             WHERE is_active = 1
               AND LOWER(gateway) = ?
               AND (tenant_code IS NULL OR tenant_code = '')
             ORDER BY id DESC
             LIMIT 1
        ";
        $st = $conn->prepare($sql);
        if ($st) {
            $st->bind_param('s', $gateway);
            $st->execute();
            $row = $st->get_result()->fetch_assoc();
            $st->close();
            if (!empty($row['sender_id'])) return (string)$row['sender_id'];
        }
    } catch (\Throwable $e) {
        sms_debug_log("Global senderId lookup error: " . $e->getMessage());
    }

    return $fallback;
}

/* ---------- Low-level sender ---------- */
/** Returns [bool $ok, string $statusOrCode, ?string $rawBody] */
function send_sms(string $to, string $message, string $gateway = SMS_DEFAULT_GATEWAY, ?mysqli $conn = null, ?string $tenantCode = null): array
{
    $msisdn  = sms_sanitize_msisdn($to);
    $message = sms_truncate($message);
    if (!$msisdn || $message === '') {
        sms_debug_log("send_sms invalid input: to='$to' msisdn='$msisdn' len=".strlen($message));
        return [false, 'INVALID_INPUT', null];
    }

    // ✅ DB sender id
    $senderId = sms_get_sender_id_from_table($conn, $gateway, $tenantCode);

    switch (strtolower($gateway)) {
        case 'zamtel': {
            $url = sprintf(
                'https://bulksms.zamtel.co.zm/api/v2.1/action/send/api_key/%s/contacts/%s/senderId/%s/message/%s',
                rawurlencode(ZAMTEL_API_KEY),
                rawurlencode($msisdn),
                rawurlencode($senderId),
                rawurlencode($message)
            );

            $res    = http_simple_get($url);
            $ok     = $res['ok'] ?? false;
            $status = (string)($res['status'] ?? 0);
            $body   = $res['body'] ?? null;

            // Interpret JSON if present
            if ($body) {
                $json = json_decode($body, true);
                if (is_array($json)) {
                    if (isset($json['status']) && strtolower((string)$json['status']) === 'success') {
                        $ok = $ok && true;
                    } elseif (isset($json['success']) && $json['success'] === true) {
                        $ok = $ok && true;
                    } else {
                        if (($res['status'] ?? 0) === 200) $ok = false;
                    }
                }
            }

            sms_debug_log("ZAMTEL senderId=$senderId to=$msisdn http=$status ok=".($ok?'1':'0')." body=".substr((string)$body,0,500));
            return [$ok, $status, $body];
        }

        case 'airtel':
        case 'mtn':
            sms_debug_log("Gateway '$gateway' not implemented.");
            return [false, 'UNIMPLEMENTED', null];

        default:
            sms_debug_log("Unknown gateway '$gateway'.");
            return [false, 'UNKNOWN_GATEWAY', null];
    }
}

/* ---------- (Voucher & Payment receipt helpers kept for completeness) ---------- */

function sms_get_user(mysqli $conn, int $userId): ?array {
    $st = $conn->prepare("SELECT id, full_name, phone_number FROM users WHERE id=? LIMIT 1");
    $st->bind_param('i', $userId);
    $st->execute();
    $u = $st->get_result()->fetch_assoc();
    $st->close();
    if (!$u) return null;

    return [
        'id'    => (int)$u['id'],
        'name'  => $u['full_name'] ?: 'User',
        'phone' => $u['phone_number'] ?? null,
    ];
}

function sms_get_voucher_core(mysqli $conn, int $voucherId): ?array {
    $st = $conn->prepare("
        SELECT id, voucher_no, payee, voucher_date, bank_account_name, bank_account_no,
               COALESCE(total_debit,0)  AS td,
               COALESCE(total_credit,0) AS tc,
               status,
               prepared_by_user_id, checked_by_user_id, authorized_by_user_id, approved_by_user_id
          FROM vouchers WHERE id=? LIMIT 1
    ");
    $st->bind_param('i', $voucherId);
    $st->execute();
    $v = $st->get_result()->fetch_assoc();
    $st->close();
    if (!$v) return null;

    $amt = max((float)$v['td'], (float)$v['tc']);
    return [
        'id'      => (int)$v['id'],
        'no'      => (string)$v['voucher_no'],
        'payee'   => (string)$v['payee'],
        'date'    => (string)$v['voucher_date'],
        'bank'    => (string)$v['bank_account_name'],
        'bank_no' => (string)$v['bank_account_no'],
        'amount'  => $amt,
        'status'  => (string)$v['status'],
        'prepared_by_user_id'   => (int)$v['prepared_by_user_id'],
        'checked_by_user_id'    => (int)$v['checked_by_user_id'],
        'authorized_by_user_id' => (int)$v['authorized_by_user_id'],
        'approved_by_user_id'   => (int)$v['approved_by_user_id'],
    ];
}

function sms_money(float $n): string {
    return 'K ' . number_format($n, 2);
}

function notify_payment_success(
    string $fullName,
    string $phone,
    float $amountPaid,
    string $txRefOrReceiptNo,
    float $newBalance,
    string $gateway = SMS_DEFAULT_GATEWAY,
    ?string $transactionId = null,
    ?mysqli $conn = null,
    ?string $tenantCode = null
): bool {
    $msisdn = sms_sanitize_msisdn($phone);
    if (!$msisdn) return false;

    $base  = defined('APP_BASE_URL') ? APP_BASE_URL : sms_base_url();
    $query = ['tx_ref' => $txRefOrReceiptNo, 'status' => 'successful'];
    if (!empty($transactionId)) $query['transaction_id'] = $transactionId;
    $link = rtrim($base, '/') . '/printClientReceipt?' . http_build_query($query);

    $msg = "Dear Client, Payment of K" . number_format($amountPaid, 2)
         . " received on receipt #{$txRefOrReceiptNo}. New balance: K"
         . number_format($newBalance, 2)
         . ". Receipt: {$link}. Thank you.";

    [$ok] = send_sms($msisdn, sms_truncate($msg), $gateway, $conn, $tenantCode);
    return $ok;
}

/* --------------------------------------------------
   OPTIONAL: SQL to create the sender table (run once)
--------------------------------------------------- */
/*
CREATE TABLE sms_sender_ids (
  id INT AUTO_INCREMENT PRIMARY KEY,
  gateway VARCHAR(20) NOT NULL,
  sender_id VARCHAR(50) NOT NULL,
  tenant_code VARCHAR(30) NULL,
  is_active TINYINT(1) NOT NULL DEFAULT 1,
  created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  INDEX idx_gateway_active (gateway, is_active),
  INDEX idx_tenant_gateway (tenant_code, gateway)
);

-- Example insert (global)
INSERT INTO sms_sender_ids (gateway, sender_id, tenant_code, is_active)
VALUES ('zamtel', 'Forward2026', NULL, 1);
*/