<?php

namespace Core\App\Services;

/**
 * WhatsApp Notification Service
 * Supports: CallMeBot, Twilio, Meta (WhatsApp Business API), UltraMsg
 */
class WhatsAppService
{
    private array $config;

    public function __construct(array $config)
    {
        $this->config = $config;
    }

    /* =====================================================
       FACTORY — load from DB
    ===================================================== */
    public static function fromSettings(): ?self
    {
        try {
            $db   = \db();
            $stmt = $db->prepare("
                SELECT is_active, config
                FROM tracking_integrations
                WHERE provider = 'whatsapp'
                LIMIT 1
            ");
            $stmt->execute();
            $row = $stmt->fetch(\PDO::FETCH_ASSOC);

            if (!$row || !(int)$row['is_active']) {
                return null;
            }

            $cfg = json_decode($row['config'], true) ?: [];
            if (empty($cfg['provider'])) {
                return null;
            }

            return new self($cfg);
        } catch (\Throwable $e) {
            return null;
        }
    }

    /* =====================================================
       SEND — dispatcher
    ===================================================== */
    public function send(string $phone, string $message, array $context = []): array
    {
        $phone = $this->normalizePhone($phone);

        $result = match($this->config['provider'] ?? '') {
            'callmebot' => $this->sendCallMeBot($phone, $message),
            'twilio'    => $this->sendTwilio($phone, $message),
            'meta'      => $this->sendMeta($phone, $message),
            'ultramsg'  => $this->sendUltraMsg($phone, $message),
            default     => ['success' => false, 'error' => 'Unknown provider'],
        };

        // Log every send attempt to whatsapp_messages table
        $this->logMessage($phone, $message, $result, $context);

        return $result;
    }

    private function logMessage(string $phone, string $message, array $result, array $context = []): void
    {
        try {
            $db = \db();
            // Auto-create table if missing (safe fallback)
            $db->exec("
                CREATE TABLE IF NOT EXISTS `whatsapp_messages` (
                    `id`          INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
                    `type`        ENUM('auto','marketing') NOT NULL DEFAULT 'auto',
                    `event`       VARCHAR(50)  DEFAULT NULL,
                    `campaign`    VARCHAR(100) DEFAULT NULL,
                    `phone`       VARCHAR(50)  NOT NULL,
                    `customer_id` INT(10) UNSIGNED DEFAULT NULL,
                    `order_id`    INT(10) UNSIGNED DEFAULT NULL,
                    `message`     TEXT         NOT NULL,
                    `provider`    VARCHAR(30)  DEFAULT NULL,
                    `status`      ENUM('sent','failed','pending') NOT NULL DEFAULT 'pending',
                    `error`       VARCHAR(500) DEFAULT NULL,
                    `sent_at`     DATETIME     DEFAULT NULL,
                    `created_at`  DATETIME     NOT NULL DEFAULT current_timestamp(),
                    PRIMARY KEY (`id`),
                    KEY `idx_order` (`order_id`),
                    KEY `idx_sent_at` (`sent_at`)
                ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
            ");

            $stmt = $db->prepare("
                INSERT INTO whatsapp_messages
                    (type, event, phone, order_id, message, provider, status, error, sent_at)
                VALUES
                    (:type, :event, :phone, :order_id, :message, :provider, :status, :error, :sent_at)
            ");
            $stmt->execute([
                ':type'     => $context['type']     ?? 'auto',
                ':event'    => $context['event']    ?? null,
                ':phone'    => $phone,
                ':order_id' => $context['order_id'] ?? null,
                ':message'  => $message,
                ':provider' => $this->config['provider'] ?? 'unknown',
                ':status'   => $result['success'] ? 'sent' : 'failed',
                ':error'    => $result['success'] ? null : ($result['error'] ?? 'unknown'),
                ':sent_at'  => $result['success'] ? date('Y-m-d H:i:s') : null,
            ]);
        } catch (\Throwable $e) {
            // Logging must never crash the app
        }
    }

    /* =====================================================
       CALLMEBOT — Free, simple
       Requires: apikey + phone registered on callmebot.com
    ===================================================== */
    private function sendCallMeBot(string $phone, string $message): array
    {
        $apiKey = $this->config['callmebot_apikey'] ?? '';
        if (!$apiKey) {
            return ['success' => false, 'error' => 'CallMeBot API key missing'];
        }

        $url = 'https://api.callmebot.com/whatsapp.php?' . http_build_query([
            'phone'   => $phone,
            'text'    => $message,
            'apikey'  => $apiKey,
        ]);

        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT        => 15,
        ]);
        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        $success = $httpCode === 200 && str_contains((string)$response, 'Message queued');

        return [
            'success'  => $success,
            'provider' => 'callmebot',
            'response' => $response,
            'error'    => $success ? null : ($response ?: 'HTTP ' . $httpCode),
        ];
    }

    /* =====================================================
       TWILIO — Paid, reliable
       Requires: account_sid, auth_token, from_number
    ===================================================== */
    private function sendTwilio(string $phone, string $message): array
    {
        $sid   = $this->config['twilio_sid']   ?? '';
        $token = $this->config['twilio_token'] ?? '';
        $from  = $this->config['twilio_from']  ?? '';

        if (!$sid || !$token || !$from) {
            return ['success' => false, 'error' => 'Twilio credentials missing'];
        }

        $url  = "https://api.twilio.com/2010-04-01/Accounts/{$sid}/Messages.json";
        $data = [
            'From' => 'whatsapp:' . $from,
            'To'   => 'whatsapp:' . $phone,
            'Body' => $message,
        ];

        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST           => true,
            CURLOPT_POSTFIELDS     => http_build_query($data),
            CURLOPT_USERPWD        => "{$sid}:{$token}",
            CURLOPT_TIMEOUT        => 15,
        ]);
        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        $decoded = json_decode($response, true);
        $success = $httpCode === 201 && !empty($decoded['sid']);

        return [
            'success'  => $success,
            'provider' => 'twilio',
            'sid'      => $decoded['sid'] ?? null,
            'error'    => $success ? null : ($decoded['message'] ?? 'HTTP ' . $httpCode),
        ];
    }

    /* =====================================================
       META (WhatsApp Business API)
       Requires: access_token, phone_number_id, template_name
    ===================================================== */
    private function sendMeta(string $phone, string $message): array
    {
        $token         = $this->config['meta_token']       ?? '';
        $phoneNumberId = $this->config['meta_phone_id']    ?? '';

        if (!$token || !$phoneNumberId) {
            return ['success' => false, 'error' => 'Meta credentials missing'];
        }

        $url  = "https://graph.facebook.com/v19.0/{$phoneNumberId}/messages";
        $body = json_encode([
            'messaging_product' => 'whatsapp',
            'to'                => $phone,
            'type'              => 'text',
            'text'              => ['body' => $message],
        ]);

        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST           => true,
            CURLOPT_POSTFIELDS     => $body,
            CURLOPT_HTTPHEADER     => [
                'Authorization: Bearer ' . $token,
                'Content-Type: application/json',
            ],
            CURLOPT_TIMEOUT => 15,
        ]);
        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        $decoded = json_decode($response, true);
        $success = $httpCode === 200 && !empty($decoded['messages']);

        return [
            'success'  => $success,
            'provider' => 'meta',
            'response' => $decoded,
            'error'    => $success ? null : ($decoded['error']['message'] ?? 'HTTP ' . $httpCode),
        ];
    }

    /* =====================================================
       ULTRAMSG — Easy & affordable
       Requires: instance_id, token
    ===================================================== */
    private function sendUltraMsg(string $phone, string $message): array
    {
        $instanceId = $this->config['ultramsg_instance'] ?? '';
        $token      = $this->config['ultramsg_token']    ?? '';

        if (!$instanceId || !$token) {
            return ['success' => false, 'error' => 'UltraMsg credentials missing'];
        }

        $url  = "https://api.ultramsg.com/{$instanceId}/messages/chat";
        $data = http_build_query([
            'token'   => $token,
            'to'      => $phone,
            'body'    => $message,
        ]);

        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST           => true,
            CURLOPT_POSTFIELDS     => $data,
            CURLOPT_HTTPHEADER     => ['Content-Type: application/x-www-form-urlencoded'],
            CURLOPT_TIMEOUT        => 15,
        ]);
        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        $decoded = json_decode($response, true);
        $success = !empty($decoded['sent']) && $decoded['sent'] === 'true';

        return [
            'success'  => $success,
            'provider' => 'ultramsg',
            'response' => $decoded,
            'error'    => $success ? null : ($decoded['error'] ?? 'HTTP ' . $httpCode),
        ];
    }

    /* =====================================================
       MESSAGE BUILDER — variables replacement
    ===================================================== */
    /**
     * Build WhatsApp message from template with variable substitution.
     * Supports multi-language templates: if the config has templates_ar/templates_en,
     * it selects based on the site language setting.
     *
     * @param string $template  Template key (e.g. 'order_confirmed') or raw template string
     * @param array  $order     Order data array
     * @param array  $config    Optional: WhatsApp config array (for multilingual template lookup)
     */
    public static function buildMessage(string $template, array $order, array $config = []): string
    {
        // Multi-language template support:
        // If $template is a key (like 'order_confirmed') and config has language variants,
        // select the appropriate language template
        if (!empty($config) && !str_contains($template, '{') && !str_contains($template, '\n')) {
            $siteLang = self::getSiteLang(); // 'ar' or 'en'
            $langKey  = 'templates_' . $siteLang;
            if (!empty($config[$langKey][$template])) {
                $template = $config[$langKey][$template];
            } elseif (!empty($config['templates'][$template])) {
                $template = $config['templates'][$template];
            }
        }

        $extra    = is_array($order['extra']) ? $order['extra'] : json_decode($order['extra'] ?? '{}', true);
        $pricing  = $extra['pricing']  ?? [];
        $shipping = $extra['shipping'] ?? [];

        // Negotiated price takes priority for accurate total
        $total = $extra['pricing']['negotiated_price']
              ?? $pricing['total']
              ?? $order['total_amount']
              ?? 0;

        $vars = [
            '{name}'         => $order['full_name']                   ?? '',
            '{order_id}'     => '#' . ($order['id']                   ?? ''),
            '{total}'        => $total . ' ' . ($pricing['currency']  ?? 'DZD'),
            '{product}'      => $extra['product']['name']             ?? '',
            '{tracking}'     => $shipping['tracking']                 ?? '',
            '{provider}'     => strtoupper($shipping['provider']      ?? ''),
            '{status}'       => $shipping['status']                   ?? '',
            '{city}'         => $shipping['destination']['city_name'] ?? ($order['city_name'] ?? ''),
            '{phone}'        => $order['phone']                       ?? '',
            '{address}'      => $order['address']                     ?? '',
            '{date}'         => date('d/m/Y'),
            '{store_name}'   => self::getStoreName(),
        ];

        return str_replace(array_keys($vars), array_values($vars), $template);
    }

    /**
     * Get site language from settings (ar/en).
     */
    private static function getSiteLang(): string
    {
        try {
            $stmt = \db()->prepare("SELECT setting_value FROM settings WHERE setting_key = 'app_lang' LIMIT 1");
            $stmt->execute();
            $lang = (string)$stmt->fetchColumn();
            return in_array($lang, ['ar', 'en'], true) ? $lang : 'ar';
        } catch (\Throwable $e) {
            return 'ar';
        }
    }

    /* =====================================================
       HELPERS
    ===================================================== */
    private function normalizePhone(string $phone): string
    {
        $phone = preg_replace('/\D/', '', $phone);
        // الجزائر: 05xxxxxxxx → 2135xxxxxxxx
        if (strlen($phone) === 10 && str_starts_with($phone, '0')) {
            $phone = '213' . ltrim($phone, '0');
        }
        // إضافة + إذا لم يكن موجوداً
        if (!str_starts_with($phone, '+')) {
            $phone = '+' . $phone;
        }
        return $phone;
    }

    private static function getStoreName(): string
    {
        try {
            $stmt = \db()->prepare("SELECT setting_value FROM settings WHERE setting_key='site_name' LIMIT 1");
            $stmt->execute();
            return $stmt->fetchColumn() ?: 'Store';
        } catch (\Throwable $e) {
            return 'Store';
        }
    }

    public function getProvider(): string
    {
        return $this->config['provider'] ?? 'unknown';
    }

    public function isEnabled(string $event): bool
    {
        return !empty($this->config['events'][$event]);
    }
}