<?php

namespace App\Libraries;

/**
 * WhatsApp Executor — UltraMsg integration
 *
 * UltraMsg is one of the cheapest WhatsApp API providers (~$15/mo for 5 000 msgs).
 * Sign up at https://ultramsg.com and create an instance to get your
 * ULTRAMSG_INSTANCE_ID and ULTRAMSG_TOKEN credentials.
 *
 * Key features used:
 *   - contacts/check  → verify if a phone number has WhatsApp
 *   - messages/chat   → send a text message
 */
class WhatsappExecutor
{
    private string $instanceId;
    private string $token;
    private string $baseUrl;

    public function __construct()
    {
        $this->instanceId = env('ULTRAMSG_INSTANCE_ID', '') ?: getenv('ULTRAMSG_INSTANCE_ID') ?: '';
        $this->token      = env('ULTRAMSG_TOKEN', '')       ?: getenv('ULTRAMSG_TOKEN')       ?: '';
        $this->baseUrl    = rtrim(env('ULTRAMSG_URL', '') ?: getenv('ULTRAMSG_URL') ?: 'https://api.ultramsg.com', '/');

        // If DotEnv failed to load (e.g. parse error earlier in .env), read directly from file
        if (empty($this->instanceId) || empty($this->token)) {
            $this->loadEnvDirect();
        }

        log_message('error', '[whatsapp] __construct instanceId=' . $this->instanceId . ' token=' . substr($this->token, 0, 6) . '...'
            . ' | $_ENV[ULTRAMSG_INSTANCE_ID]=' . ($_ENV['ULTRAMSG_INSTANCE_ID'] ?? 'NOT_SET')
            . ' | $_ENV[SMS_FROM]=' . ($_ENV['SMS_FROM'] ?? 'NOT_SET')
            . ' | getenv(ULTRAMSG_INSTANCE_ID)=' . (getenv('ULTRAMSG_INSTANCE_ID') ?: 'NOT_SET')
        );
    }

    /**
     * Check if a phone number has WhatsApp registered.
     *
     * @param  string $phone  E.164 format recommended, e.g. +255712345678
     * @return bool
     */
    public function hasWhatsapp(string $phone): bool
    {
        if (!$this->isConfigured()) {
            log_message('warning', '[whatsapp] UltraMsg not configured, skipping number check');
            return false;
        }

        $phone  = $this->normalizePhone($phone);
        $chatId = $phone . '@c.us';
        $url    = "{$this->baseUrl}/{$this->instanceId}/contacts/check"
                . "?token={$this->token}&chatId=" . urlencode($chatId);

        $response = $this->get($url);

        if ($response === false) {
            log_message('error', "[whatsapp] contacts/check request failed for {$phone}");
            return false;
        }

        // UltraMsg returns: {"status":"valid","chatId":"...@lid"} when on WhatsApp
        log_message('error', "[whatsapp] contacts/check raw: " . json_encode($response));
        $onWa = isset($response['status']) && $response['status'] === 'valid'
             || ($response['onWhatsapp'] ?? $response['numberExists'] ?? false);
        log_message('debug', "[whatsapp] hasWhatsapp({$phone}) => " . ($onWa ? 'true' : 'false'));
        return (bool) $onWa;
    }

    /**
     * Send a plain-text WhatsApp message.
     *
     * @param  string $phone  Target phone number
     * @param  string $text   Message body
     * @return bool
     */
    public function sendMessage(string $phone, string $text): bool
    {
        if (!$this->isConfigured()) {
            log_message('error', '[whatsapp] Cannot send — UltraMsg not configured');
            return false;
        }

        $phone   = $this->normalizePhone($phone);
        $payload = http_build_query([
            'token' => $this->token,
            'to'    => $phone,
            'body'  => $text,
        ]);

        $url      = "{$this->baseUrl}/{$this->instanceId}/messages/chat";
        $response = $this->curlPost($url, $payload);

        if ($response === false) {
            log_message('error', "[whatsapp] messages/chat request failed for {$phone}");
            return false;
        }

        log_message('error', "[whatsapp] messages/chat raw: " . json_encode($response));

        // UltraMsg returns: {"sent":"true","id":"..."} or {"error":"..."}
        $sent = isset($response['sent']) && filter_var($response['sent'], FILTER_VALIDATE_BOOLEAN);
        if ($sent) {
            log_message('error', "[whatsapp] ✅ Text sent to {$phone}");
        } else {
            log_message('error', "[whatsapp] ❌ Text send failed: " . json_encode($response));
        }
        return $sent;
    }

    /**
     * Send an image with optional caption via WhatsApp.
     *
     * @param  string $phone    Target phone number
     * @param  string $imageUrl Publicly accessible URL to the image
     * @param  string $caption  Optional caption text
     * @return bool
     */
    public function sendImage(string $phone, string $imageUrl, string $caption = ''): bool
    {
        if (!$this->isConfigured()) {
            log_message('error', '[whatsapp] Cannot send image — UltraMsg not configured');
            return false;
        }

        $phone   = $this->normalizePhone($phone);
        $payload = http_build_query([
            'token'   => $this->token,
            'to'      => $phone,
            'image'   => $imageUrl,
            'caption' => $caption,
        ]);

        $url      = "{$this->baseUrl}/{$this->instanceId}/messages/image";
        $response = $this->curlPost($url, $payload);

        if ($response === false) {
            log_message('error', "[whatsapp] messages/image failed for {$phone}");
            return false;
        }

        log_message('error', "[whatsapp] messages/image raw: " . json_encode($response));
        $sent = isset($response['sent']) && filter_var($response['sent'], FILTER_VALIDATE_BOOLEAN);
        return $sent;
    }

    /**
     * Send a location pin via WhatsApp.
     *
     * @param  string $phone   Target phone number
     * @param  float  $lat     Latitude
     * @param  float  $lng     Longitude
     * @param  string $address Human-readable address
     * @return bool
     */
    public function sendLocation(string $phone, float $lat, float $lng, string $address = ''): bool
    {
        if (!$this->isConfigured()) {
            log_message('error', '[whatsapp] Cannot send location — UltraMsg not configured');
            return false;
        }

        $phone   = $this->normalizePhone($phone);
        $payload = http_build_query([
            'token'   => $this->token,
            'to'      => $phone,
            'address' => $address,
            'lat'     => $lat,
            'lng'     => $lng,
        ]);

        $url      = "{$this->baseUrl}/{$this->instanceId}/messages/location";
        $response = $this->curlPost($url, $payload);

        if ($response === false) {
            log_message('error', "[whatsapp] messages/location failed for {$phone}");
            return false;
        }

        log_message('error', "[whatsapp] messages/location raw: " . json_encode($response));
        $sent = isset($response['sent']) && filter_var($response['sent'], FILTER_VALIDATE_BOOLEAN);
        return $sent;
    }

    /**
     * Mark a WhatsApp chat as read.
     *
     * @param  string $chatId  The chat ID to mark as read (e.g. 255712345678@c.us)
     * @return bool
     */
    public function markChatRead(string $chatId): bool
    {
        if (!$this->isConfigured()) {
            log_message('error', '[whatsapp] Cannot mark chat read — UltraMsg not configured');
            return false;
        }

        $payload = http_build_query([
            'token'  => $this->token,
            'chatId' => $chatId,
        ]);

        $url      = "{$this->baseUrl}/{$this->instanceId}/chats/read";
        $response = $this->curlPost($url, $payload);

        if ($response === false) {
            log_message('error', "[whatsapp] chats/read failed for chatId={$chatId}");
            return false;
        }

        log_message('error', "[whatsapp] chats/read raw: " . json_encode($response));
        return isset($response['done']) && $response['done'] === true;
    }

    /**
     * Returns true when both credentials are present.
     */
    public function isConfigured(): bool
    {
        return !empty($this->instanceId) && !empty($this->token);
    }

    // ── Helpers ──────────────────────────────────────────────────────────────

    /** Normalize phone — keep as-is for UltraMsg (accepts local & international) */
    private function normalizePhone(string $phone): string
    {
        return preg_replace('/[^0-9+]/', '', $phone);
    }

    /**
     * Fallback: parse .env file directly for ULTRAMSG_* keys when CI4 DotEnv
     * failed to load them (e.g. due to a parse error earlier in the file).
     */
    private function loadEnvDirect(): void
    {
        $envPath = ROOTPATH . '.env';
        if (!is_file($envPath)) {
            log_message('error', '[whatsapp] loadEnvDirect: .env not found at ' . $envPath);
            return;
        }

        foreach (file($envPath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) as $line) {
            $line = trim($line);
            if ($line === '' || $line[0] === '#') continue;
            if (!str_contains($line, '=')) continue;

            [$key, $val] = explode('=', $line, 2);
            $key = trim($key);
            $val = trim($val, " \t\"'"); // strip surrounding quotes/spaces

            if ($key === 'ULTRAMSG_INSTANCE_ID' && empty($this->instanceId)) {
                $this->instanceId = $val;
            } elseif ($key === 'ULTRAMSG_TOKEN' && empty($this->token)) {
                $this->token = $val;
            } elseif ($key === 'ULTRAMSG_URL' && $this->baseUrl === 'https://api.ultramsg.com') {
                $this->baseUrl = rtrim($val, '/');
            }
        }

        log_message('error', '[whatsapp] loadEnvDirect instanceId=' . $this->instanceId . ' token=' . substr($this->token, 0, 6) . '...');
    }

    /** GET request, returns decoded array or false */
    private function get(string $url): array|false
    {
        $curl = curl_init();
        curl_setopt_array($curl, [
            CURLOPT_URL            => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT        => 15,
            CURLOPT_SSL_VERIFYHOST => 0,
            CURLOPT_SSL_VERIFYPEER => 0,
        ]);
        $body = curl_exec($curl);
        $err  = curl_error($curl);
        $code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
        curl_close($curl);
        log_message('error', "[whatsapp] GET {$url} HTTP={$code} err={$err} body={$body}");
        if ($err || $body === false) return false;
        return json_decode($body, true) ?? [];
    }

    /** POST request with x-www-form-urlencoded payload */
    private function curlPost(string $url, string $payload): array|false
    {
        $curl = curl_init();
        curl_setopt_array($curl, [
            CURLOPT_URL            => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_ENCODING       => '',
            CURLOPT_MAXREDIRS      => 10,
            CURLOPT_TIMEOUT        => 30,
            CURLOPT_SSL_VERIFYHOST => 0,
            CURLOPT_SSL_VERIFYPEER => 0,
            CURLOPT_HTTP_VERSION   => CURL_HTTP_VERSION_1_1,
            CURLOPT_CUSTOMREQUEST  => 'POST',
            CURLOPT_POSTFIELDS     => $payload,
            CURLOPT_HTTPHEADER     => [
                'content-type: application/x-www-form-urlencoded',
            ],
        ]);
        $body = curl_exec($curl);
        $err  = curl_error($curl);
        curl_close($curl);
        if ($err || $body === false) {
            log_message('error', "[whatsapp] curlPost error: {$err}");
            return false;
        }
        return json_decode($body, true) ?? [];
    }
}
