<?php
namespace EasyChat\Library\Messenger\Marketplace;

use EasyChat\Model\Marketplace as MarketplaceModel;








final class MarketplaceAdminPresenter {
    private $model;

    public function __construct($registry, MarketplaceModel $model = null) {
        $this->model = $model ?: new MarketplaceModel($registry);
    }

    public function build(): array {
        $providers = self::providerDefinitions();
        $empty_groups = array_fill_keys(array_keys($providers), []);

        try {
            $accounts = $this->model->listAccounts();
            $streams = $this->model->listAccountStreams();
        } catch (\Throwable $error) {
             
             
            return [
                'providers' => $providers,
                'accounts_by_provider' => $empty_groups,
                'storage_ready' => false,
            ];
        }

        return [
            'providers' => $providers,
            'accounts_by_provider' => self::presentAccounts($accounts, $streams),
            'storage_ready' => true,
        ];
    }

    public static function presentAccounts(array $accounts, array $streams): array {
        $groups = array_fill_keys(array_keys(self::providerDefinitions()), []);
        $streams_by_channel = [];

        foreach ($streams as $stream) {
            $channel_id = (int)($stream['channel_id'] ?? 0);
            if ($channel_id > 0) {
                $streams_by_channel[$channel_id][] = $stream;
            }
        }

        foreach ($accounts as $account) {
            $provider = self::normalizeProvider((string)($account['provider'] ?? ''));
            if ($provider === '') {
                continue;
            }

            $channel_id = (int)($account['channel_id'] ?? 0);
            $capabilities = self::decode((string)($account['capabilities_json'] ?? ''));
            $settings = self::decode((string)($account['settings_json'] ?? ''));
            $presented_streams = [];

            foreach (($streams_by_channel[$channel_id] ?? []) as $stream) {
                $stream_code = (string)($stream['stream'] ?? '');
                $access = is_array($capabilities['stream_access'][$stream_code] ?? null)
                    ? $capabilities['stream_access'][$stream_code]
                    : [];
                $stream['available'] = array_key_exists('available', $access)
                    ? (bool)$access['available']
                    : null;
                $stream['missing_methods'] = is_array($access['missing_read_methods'] ?? null)
                    ? $access['missing_read_methods']
                    : [];
                $presented_streams[] = $stream;
            }

            $account['capabilities'] = $capabilities;
            $ozon_key_health = $provider === 'ozon'
                ? self::ozonKeyHealth((string)($capabilities['key_expires_at'] ?? ''))
                : [];
            $account['token_health'] = [
                'type' => (string)($capabilities['token_type'] ?? 'unknown'),
                'label' => (string)($capabilities['token_type_label'] ?? ''),
                'expires_at' => (string)($capabilities['token_expires_at'] ?? ''),
                'read_only' => !empty($capabilities['token_read_only']),
                'permissions' => is_array($capabilities['token_permissions'] ?? null)
                    ? $capabilities['token_permissions']
                    : [],
            ];
            if ($provider === 'ozon') {
                $account['token_health']['key'] = $ozon_key_health;
            }
            $account['streams'] = $presented_streams;
            $account['has_credentials'] = trim((string)($account['credentials_json'] ?? '')) !== '';
            $account['options'] = [
                'ai_auto_reply' => !empty($settings['ai_auto_reply']),
            ];
            $account['webhook_url'] = $provider === 'yandex_market'
                ? rtrim((string)HTTP_SERVER, '/') . '/index.php?route=messenger/webhook&provider=yandex_market&id='
                    . rawurlencode((string)($account['public_id'] ?? ''))
                : '';
            $account['last_error_message'] = trim((string)($account['last_error'] ?? '')) !== ''
                ? self::errorMessage((string)$account['last_error'])
                : '';
            unset($account['credentials_json'], $account['settings_json'], $account['capabilities_json']);
            $groups[$provider][] = $account;
        }

        return $groups;
    }

    




    public static function ozonKeyHealth(string $expires_at, ?int $now = null): array {
        $expires_at = trim($expires_at);
        $timestamp = $expires_at !== '' ? strtotime($expires_at) : false;
        if ($timestamp === false || $timestamp <= 0) {
            return [
                'status' => 'unknown', 'expires_at' => $expires_at,
                'expires_label' => '', 'days_left' => null,
                'requires_attention' => false, 'message' => '',
            ];
        }

        $now = $now ?? time();
        $seconds_left = $timestamp - $now;
        $days_left = $seconds_left > 0 ? (int)ceil($seconds_left / 86400) : 0;
        $status = $seconds_left <= 0 ? 'expired' : ($seconds_left <= 30 * 86400 ? 'expiring' : 'valid');
        $label = date('d.m.Y', $timestamp);
        $message = $status === 'expired'
            ? 'Срок действия ключа Ozon закончился. Выпустите новый ключ.'
            : ($status === 'expiring'
                ? 'Ключ Ozon действует до ' . $label . '. Желательно перевыпустить его заранее.'
                : 'Ключ Ozon действует до ' . $label . '.');

        return [
            'status' => $status, 'expires_at' => $expires_at,
            'expires_label' => $label, 'days_left' => $days_left,
            'requires_attention' => $status !== 'valid', 'message' => $message,
        ];
    }

    public static function attentionSummary(array $accounts_by_provider): array {
        $attention = [];
        foreach ((array)($accounts_by_provider['ozon'] ?? []) as $account) {
            $health = $account['token_health']['key'] ?? [];
            if (!empty($health['requires_attention'])) {
                $attention[] = $health;
            }
        }
        if (!$attention) {
            return ['count' => 0, 'key' => '', 'title' => '', 'detail' => '', 'route' => ''];
        }
        usort($attention, static function ($a, $b) {
            return ((int)($a['days_left'] ?? 0)) <=> ((int)($b['days_left'] ?? 0));
        });
        $health = $attention[0];
        return [
            'count' => count($attention),
            'key' => 'ozon-key:' . (string)($health['status'] ?? 'unknown') . ':' . (string)($health['expires_at'] ?? ''),
            'title' => 'Ozon требует внимания',
            'detail' => (string)($health['message'] ?? 'Проверьте срок ключа Ozon.'),
            'route' => 'index.php?route=integration&tab=ozon',
        ];
    }

    public static function normalizeProvider(string $provider): string {
        $provider = strtolower(trim($provider));
        return isset(self::providerDefinitions()[$provider]) ? $provider : '';
    }

    public static function providerDefinitions(): array {
        return MarketplaceProviderCatalog::all();
    }

    public static function errorMessage(string $code): string {
        $messages = [
            'api_token_required' => 'Введите API-токен Wildberries.',
            'wb_token_format_invalid' => 'Это не похоже на полный токен WB. Скопируйте его целиком из раздела «Интеграции по API».',
            'client_id_required' => 'Введите Client ID кабинета Ozon.',
            'api_key_required' => 'Введите API key кабинета маркетплейса.',
            'auth_failed' => 'Ключ не принят площадкой. Проверьте реквизиты и срок действия.',
            'permission_denied' => 'Ключ работает, но ему не хватает прав на коммуникации.',
            'subscription_required' => 'Для чатов этого кабинета нужна подходящая подписка Ozon.',
            'rate_limited' => 'Площадка временно ограничила частоту запросов. Повторите позже.',
            'marketplace_unavailable' => 'API площадки временно недоступен. Уже подключенные потоки продолжат повторять синхронизацию.',
            'transport_failed' => 'Не удалось установить защищенное соединение с площадкой.',
            'notification_check_failed' => 'Ozon не смог проверить адрес уведомлений. Резервная синхронизация по расписанию продолжит работать.',
            'notification_list_failed' => 'Ключ не даёт управлять уведомлениями Ozon. Резервная синхронизация по расписанию продолжит работать.',
            'notification_setup_failed' => 'Быстрые уведомления Ozon пока не включились. Резервная сверка уже работает.',
            'notification_update_failed' => 'Ozon не обновил адрес быстрых уведомлений. Резервная сверка продолжит работать.',
            'notification_set_failed' => 'Ozon не сохранил адрес быстрых уведомлений. Резервная сверка продолжит работать.',
            'notification_enable_failed' => 'Ozon не включил быстрые уведомления. Резервная сверка продолжит работать.',
            'notification_url_inactive' => 'Ozon не смог обратиться к callback EasyChat. Проверьте HTTPS и доступность сайта извне.',
            'webhook_url_invalid' => 'Адрес EasyChat для уведомлений должен быть публичным HTTPS-адресом без нестандартного порта.',
            'marketplace_account_identity_mismatch' => 'Этот ключ относится к другому кабинету. Подключите его как новый кабинет.',
            'marketplace_account_identity_missing' => 'Wildberries не вернул стабильный ID кабинета. Проверьте тип токена и доступ к сведениям продавца.',
            'marketplace_account_provider_mismatch' => 'Выбранный кабинет относится к другой площадке. Добавьте его отдельным подключением.',
            'marketplace_account_conflict' => 'Этот кабинет уже подключен в EasyChat.',
            'marketplace_account_not_found' => 'Подключенный кабинет не найден. Обновите страницу и повторите действие.',
            'marketplace_account_inactive' => 'Кабинет отключен. Сначала подключите его снова.',
            'marketplace_stream_unknown' => 'EasyChat не распознал этот раздел обращений. Обновите страницу.',
            'marketplace_stream_permission_missing' => 'У ключа нет прав на этот тип обращений.',
            'install_secret_missing' => 'Установка EasyChat не завершила настройку защищенного хранилища. Запустите обновление модуля и повторите подключение.',
            'marketplace_host_not_allowed' => 'EasyChat заблокировал небезопасный адрес внешнего API.',
            'marketplace_response_too_large' => 'Площадка вернула слишком большой ответ. Синхронизация остановлена безопасно и будет повторена позже.',
            'marketplace_cursor_stalled' => 'Площадка не продвинула страницу выдачи. EasyChat ничего не пропустил и повторит сверку позже.',
            'endpoint_or_resource_not_found' => 'Площадка не нашла запрошенный раздел. Проверьте права ключа и доступность функции в кабинете.',
            'marketplace_conflict' => 'Состояние обращения уже изменилось на площадке. EasyChat выполнит сверку.',
            'marketplace_action_outcome_unknown' => 'Площадка не подтвердила результат. EasyChat сначала сверит состояние и не повторит действие вслепую.',
            'marketplace_action_in_progress' => 'Это действие уже отправляется. Дождитесь сверки с площадкой.',
            'marketplace_action_not_allowed' => 'Площадка больше не разрешает это действие. Обновите диалог.',
            'marketplace_action_audit_failed' => 'EasyChat не смог безопасно зарегистрировать действие. Ничего не отправлено, повторите позже.',
            'marketplace_action_failed' => 'Действие не отправлено из-за внутренней ошибки. Обновите обращение и повторите позже.',
            'marketplace_thread_not_found' => 'Обращение не найдено или уже было обновлено. Откройте диалог заново.',
            'marketplace_channel_inactive' => 'Кабинет отключен. Подключите его снова в разделе интеграций.',
            'marketplace_provider_unavailable' => 'Модуль интеграции временно недоступен. Обновите EasyChat и повторите проверку.',
            'review_comment_not_allowed' => 'Ozon не разрешает отвечать на отзыв без текста, фото или видео.',
            'answer_text_required' => 'Введите текст ответа перед публикацией.',
            'answer_text_too_short' => 'Ответ слишком короткий. Добавьте пояснение для покупателя.',
            'message_text_too_long' => 'Текст длиннее лимита площадки. Сократите сообщение и отправьте снова.',
            'attachment_limit_exceeded' => 'Выбрано больше файлов, чем разрешает площадка.',
            'attachment_size_exceeded' => 'Один из файлов или вся группа превышает лимит площадки.',
            'attachment_format_not_supported' => 'Площадка не принимает один из выбранных форматов.',
            'marketplace_attachment_permission_missing' => 'Ключ разрешает читать чат, но не разрешает отправлять файлы.',
            'marketplace_account_required' => 'Выберите подключенный кабинет Ozon.',
            'marketplace_start_permission_missing' => 'У API key нет права создавать чат по отправлению.',
            'marketplace_start_not_supported' => 'Эта площадка не разрешает продавцу начинать диалог.',
            'marketplace_start_failed' => 'Ozon не создал диалог. Проверьте номер отправления и доступность чатов в тарифе.',
            'marketplace_start_message_failed' => 'Чат создан, но первое сообщение не было подтверждено. EasyChat сверит его перед повтором.',
            'marketplace_start_response_invalid' => 'Ozon создал запрос, но не вернул идентификатор чата. EasyChat выполнит сверку.',
            'marketplace_request_id_invalid' => 'Не удалось защитить повторную отправку. Закройте окно и откройте его снова.',
            'ozon_posting_number_invalid' => 'Введите номер отправления Ozon без пробелов.',
            'yandex_market_context_invalid' => 'Выберите заказ или возврат и укажите его числовой ID в Яндекс Маркете.',
            'return_comment_required' => 'Для этого решения площадка требует комментарий.',
            'return_rejection_reason_not_allowed' => 'Эта причина больше недоступна для заявки. Обновите диалог.',
            'return_amount_invalid' => 'Проверьте сумму компенсации или обратной доставки.',
            'csrf_validation_failed' => 'Сессия устарела. Обновите страницу и повторите действие.',
        ];

        return $messages[$code] ?? 'Не удалось выполнить действие. Проверьте состояние подключения и повторите попытку.';
    }

    private static function decode(string $json): array {
        $value = json_decode($json, true);
        return is_array($value) ? $value : [];
    }
}
