<?php
namespace EasyChat\Library\Messenger;

use EasyChat\Library\AttachmentPolicy;
use PHPMax\Client;
use PHPMax\Config\ClientOptions;
use PHPMax\Files\File as PHPMaxFile;
use PHPMax\Files\Photo as PHPMaxPhoto;







class MaxProvider implements MessengerProviderInterface {

    const PROVIDER = 'max';

    private $registry;

    public function __construct($registry = null) {
        $this->registry = $registry;
        MaxRuntime::requireAutoload();
    }

    public function providerCode(): string {
        return self::PROVIDER;
    }

    public function getBotInfo(string $token): array {
        return ['success' => false, 'error' => 'webhook_not_supported'];
    }

    public function syncWebhook(array $channel, string $token, string $webhook_url, string $secret): array {
        return ['success' => false, 'error' => 'webhook_not_supported'];
    }

    public function parseWebhook(array $payload): array {
        return MaxEventNormalizer::fromArray($payload);
    }

    public function sendMessage(string $token, string $external_user_id, string $text, array $attachments = [], array $options = []): array {
        $config = $this->decodeClientConfig($token);
        $chat_id = $this->resolveRecipientChatId($options, $external_user_id, $config);
        if ($chat_id <= 0) {
            return ['success' => false, 'error' => 'recipient_missing'];
        }

        $client_options = $this->clientOptionsFromConfig($config);
        if (!$client_options) {
            return ['success' => false, 'error' => 'session_missing'];
        }

        try {
            $client = new Client($client_options);
            $sent = $client->withOpenSession(function (Client $client) use ($chat_id, $text, $attachments) {
                $phpmax_attachments = $this->uploadAttachments($client, $attachments);
                return $client->sendMessage($chat_id, mb_substr($text, 0, 4000, 'UTF-8'), null, $phpmax_attachments ?: null, true);
            });
        } catch (\Throwable $e) {
            return [
                'success' => false,
                'error' => 'api_request_failed',
                'details' => MaxRuntime::safeError($e),
                'exception_class' => get_class($e),
                'chat_hash' => MessengerLogger::hashExternalId((string)$chat_id),
            ];
        }

        return [
            'success' => true,
            'http_code' => 200,
            'external_message_id' => $sent && isset($sent->id) ? (string)$sent->id : '',
            'provider_cursor' => $sent && isset($sent->time) ? max(0, (int)$sent->time) : 0,
        ];
    }

    private function decodeClientConfig(string $token): array {
        $config = json_decode($token, true);
        return is_array($config) ? $config : [];
    }

    private function clientOptionsFromConfig(array $config): ?ClientOptions {
        if ($config === []) {
            return null;
        }
        $work_dir = (string)($config['work_dir'] ?? '');
        $session_name = (string)($config['session_name'] ?? '');
        if ($work_dir === '' || $session_name === '') {
            return null;
        }

        $options = [
            'token' => (string)($config['token'] ?? '') ?: null,
            'requestTimeout' => 12,
            'connectTimeout' => 8,
            'executionSafetyMargin' => 3,
            'telemetry' => false,
        ];
        $channel_id = (int)($config['channel_id'] ?? 0);
        if ($this->registry && $channel_id > 0) {
            return (new MaxSessionLifecycle($this->registry))->clientOptions([
                'channel_id' => $channel_id,
                'credentials_json' => json_encode($config, JSON_UNESCAPED_UNICODE),
                'settings_json' => json_encode([
                    'session_generation' => max(1, (int)($config['session_generation'] ?? 1)),
                ], JSON_UNESCAPED_UNICODE),
            ], $options, max(1, (int)($config['session_generation'] ?? 1)));
        }

        $options['workDir'] = $work_dir;
        $options['sessionName'] = $session_name;
        $options['store'] = new \PHPMax\Session\JsonFileSessionStore($work_dir, $session_name, true);
        return new ClientOptions($options);
    }

    private function resolveRecipientChatId(array $options, string $external_user_id, array $config): int {
        $explicit_chat_id = $this->numericId((string)($options['external_chat_id'] ?? ''));
        if ($explicit_chat_id !== 0) {
             
             
            return $explicit_chat_id;
        }

        $account_id = $this->positiveNumericId((string)($config['account_id'] ?? ''));
        $counterparty_id = $this->positiveNumericId((string)($options['counterparty_user_id'] ?? ''));
        if ($account_id > 0 && $counterparty_id > 0 && $account_id !== $counterparty_id) {
            $derived_chat_id = $account_id ^ $counterparty_id;
            if ($derived_chat_id > 0) {
                return $derived_chat_id;
            }
        }

         
         
        return $this->numericId($external_user_id);
    }

    private function numericId(string $value): int {
        $value = trim($value);
        return preg_match('/^-?\d+$/', $value) ? (int)$value : 0;
    }

    private function positiveNumericId(string $value): int {
        $id = $this->numericId($value);
        return $id > 0 ? $id : 0;
    }

    private function uploadAttachments(Client $client, array $attachments): array {
        $result = [];
        foreach ($attachments as $attachment) {
            $path = (string)($attachment['path'] ?? '');
            $filename = (string)($attachment['file_name'] ?? $attachment['filename'] ?? basename($path));
            $mime = (string)($attachment['mime_type'] ?? $attachment['mime'] ?? '');
            if (!is_file($path)) {
                throw new \RuntimeException('attachment_file_missing');
            }
            $extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
            if ($extension === '' && $mime !== '') {
                $extension = AttachmentPolicy::extensionForMime($mime);
            }
            $is_document = AttachmentPolicy::isDocumentExtension($extension) || AttachmentPolicy::isDocumentMime($mime);
            if ($is_document) {
                $validation = AttachmentPolicy::validateDocumentFile($path, $filename, (int)filesize($path), $this->documentMaxMb($path));
                if (empty($validation['success'])) {
                    throw new \RuntimeException('attachment_type_unsupported');
                }
                $result[] = $client->uploadFile(new PHPMaxFile(null, $path, null, $filename));
                continue;
            }
            if (!AttachmentPolicy::isMaxImageExtension($extension)) {
                throw new \RuntimeException('attachment_type_unsupported');
            }
            $result[] = $client->uploadPhoto(new PHPMaxPhoto(null, $path, null, $filename));
        }
        return $result;
    }

    private function documentMaxMb(string $path): int {
        $size = is_file($path) ? (int)filesize($path) : 0;
        return max(1, (int)ceil(max(1, $size) / 1024 / 1024));
    }
}
