<?php
namespace EasyChat\Library\Messenger;







class MaxHealthPresenter {

    private const FRESH_SECONDS = 300;

    private $lifecycle;
    private $inbox;

    public function __construct($registry, $lifecycle = null, $inbox = null) {
        $this->lifecycle = $lifecycle ?: new MaxSessionLifecycle($registry);
        $this->inbox = $inbox;
    }

    public function build(array $channel): array {
        try {
            $context = $this->lifecycle->snapshot($channel);
            $channel = $context['channel'];
            $settings = $context['settings'];
            $generation = (int)$context['generation'];
            $session = $context['session'];
        } catch (MaxSessionLifecycleBusyException $e) {
            return $this->unavailableResult(
                $channel,
                'pending',
                'Обновляем состояние',
                'Сессия MAX сейчас безопасно обновляется. Повторите проверку через несколько секунд.'
            );
        } catch (\Throwable $e) {
            return $this->unavailableResult(
                $channel,
                'error',
                'Хранилище недоступно',
                'EasyChat не может безопасно прочитать сессию MAX. Проверьте права на папку storage.'
            );
        }

        $status = (string)($channel['status'] ?? 'disabled');
        $auth = is_array($settings['auth'] ?? null) ? $settings['auth'] : [];
        $items = [
            $this->authorizationItem($status, $auth, $session, $generation, $channel),
            $this->apiItem($status, $settings, $generation),
            $this->cronItem($status, $settings, $generation, $auth),
            $this->processingItem($status, $settings, $generation, (int)($channel['channel_id'] ?? 0)),
        ];

        return [
            'channel' => $channel,
            'settings' => $settings,
            'generation' => $generation,
            'summary' => $this->summaryFromItems($status, $items),
            'items' => $items,
            'session' => $session,
        ];
    }

    private function authorizationItem(string $status, array $auth, array $session, int $generation, array $channel): array {
        if ($this->lifecycle->isAuthenticationInProgress(['auth' => $auth])) {
            return $this->item('authorization', 'Авторизация', 'pending', 'Выполняется вход', 'Завершите QR, SMS или ввод облачного пароля.');
        }
        if ((string)($auth['status'] ?? '') === 'error' && (int)($auth['session_generation'] ?? 0) === $generation) {
            return $this->item('authorization', 'Авторизация', 'error', 'Вход не завершен', $this->authErrorDetail((string)($auth['error_code'] ?? '')));
        }
        if ($status !== 'active') {
            $detail = (string)($session['status'] ?? '') === 'ready'
                ? 'Защищенная сессия сохранена и будет использована после включения.'
                : 'Включите личный MAX и выполните вход по QR или SMS.';
            return $this->item('authorization', 'Авторизация', 'disabled', 'MAX выключен', $detail);
        }
        if ((string)($session['status'] ?? '') === 'invalid') {
            return $this->item('authorization', 'Авторизация', 'error', 'Сессия повреждена', 'Выполните повторный вход по QR или SMS.');
        }
        if ((string)($session['status'] ?? '') !== 'ready') {
            return $this->item('authorization', 'Авторизация', 'warning', 'Нужен вход', 'Подключите личный MAX по QR или SMS.');
        }
        if (empty($channel['bot_user_id']) && (string)($auth['status'] ?? '') !== 'connected') {
            return $this->item('authorization', 'Авторизация', 'pending', 'Проверяем профиль', 'Защищенная сессия найдена, ожидается подтверждение учетной записи.');
        }
        return $this->item('authorization', 'Авторизация', 'ok', 'Сессия защищена', 'EasyChat хранит одну актуальную сессию для этой учетной записи.');
    }

    private function apiItem(string $status, array $settings, int $generation): array {
        if ($status !== 'active') {
            return $this->item('api', 'MAX API', 'disabled', 'Не проверяется', 'Включите личный MAX, чтобы проверить соединение.');
        }
        $ok_ts = $this->generationTimestamp($settings, 'polling_api_last_ok', $generation);
        $error_ts = $this->generationTimestamp($settings, 'polling_api_last_error', $generation);
        if ($error_ts > $ok_ts) {
            $category = (string)($settings['polling_api_last_error_category'] ?? '');
            if ($category === 'authorization') {
                return $this->item('api', 'MAX API', 'error', 'MAX отклонил сессию', 'Выполните повторный вход по QR или SMS.');
            }
            if ($category === 'storage') {
                return $this->item('api', 'MAX API', 'error', 'Сессия недоступна', 'Проверьте права на защищенную папку storage.');
            }
            if ($category === 'transport') {
                return $this->item('api', 'MAX API', 'warning', 'MAX временно не ответил', 'EasyChat повторит подключение автоматически.', $error_ts);
            }
            return $this->item('api', 'MAX API', 'error', 'Проверка не прошла', 'Откройте диагностику MAX или дождитесь следующего запуска.', $error_ts);
        }
        if ($ok_ts > 0 && time() - $ok_ts < self::FRESH_SECONDS) {
            return $this->item('api', 'MAX API', 'ok', 'MAX отвечает', 'Последняя проверка прошла успешно.', $ok_ts);
        }
        if ($ok_ts > 0) {
            return $this->item('api', 'MAX API', 'warning', 'Давно не проверялось', 'Проверьте, что отдельный MAX Cron включен.', $ok_ts);
        }
        return $this->item('api', 'MAX API', 'pending', 'Ожидает проверку', 'Первый запуск cron подтвердит соединение с MAX.');
    }

    private function cronItem(string $status, array $settings, int $generation, array $auth): array {
        if ($status !== 'active') {
            return $this->item('cron', 'Cron', 'disabled', 'MAX выключен', 'Отдельный запуск сейчас не требуется.');
        }
        if ($this->lifecycle->isAuthenticationInProgress(['auth' => $auth])) {
            return $this->item('cron', 'Cron', 'pending', 'Пауза на время входа', 'Cron продолжит работу с новым поколением сессии.');
        }
        $last_run_ts = $this->generationTimestamp($settings, 'dedicated_cron_last_run', $generation);
        $skip_reason = (int)($settings['dedicated_cron_last_skipped_generation'] ?? 0) === $generation
            ? (string)($settings['dedicated_cron_last_skipped_reason'] ?? '')
            : '';
        if ($last_run_ts > 0 && time() - $last_run_ts < self::FRESH_SECONDS) {
            $detail = $skip_reason === 'backoff'
                ? 'Задача запускается по расписанию; MAX API временно ждет повторной попытки.'
                : 'Отдельная задача MAX работает.';
            return $this->item('cron', 'Cron', 'ok', 'Запускается регулярно', $detail, $last_run_ts);
        }
        if ($last_run_ts > 0) {
            return $this->item('cron', 'Cron', 'warning', 'Давно не запускался', 'Проверьте задачу в панели хостинга.', $last_run_ts);
        }
        return $this->item('cron', 'Cron', 'pending', 'Нужно настроить', 'Добавьте отдельную команду MAX из блока ниже.');
    }

    private function processingItem(string $status, array $settings, int $generation, int $channel_id): array {
        if ($status !== 'active') {
            return $this->item('processing', 'Обработка сообщений', 'disabled', 'Не выполняется', 'MAX выключен.');
        }
        $inbox = $this->inboxStats($channel_id);
        $pending = max(0, (int)($inbox['count'] ?? 0));
        if ($pending > 0) {
            $oldest = max(0, (int)($inbox['oldest_at'] ?? 0));
            $failed = max(0, (int)($settings['polling_inbox_last_drain_failed'] ?? 0));
            return $this->item(
                'processing',
                'Обработка сообщений',
                $failed > 0 ? 'warning' : 'pending',
                'Сообщения сохранены и ждут обработки',
                'В защищенной очереди: ' . $pending . '. EasyChat повторит запись автоматически.',
                $oldest
            );
        }
        $ok_ts = $this->generationTimestamp($settings, 'polling_processing_last_ok', $generation);
        $error_ts = $this->generationTimestamp($settings, 'polling_processing_last_error', $generation);
        if ($error_ts > $ok_ts) {
            return $this->item(
                'processing',
                'Обработка сообщений',
                'error',
                'Сообщение не обработано',
                'EasyChat повторит получение. Включите диагностику, если ошибка повторяется.',
                $error_ts
            );
        }
        if ($ok_ts > 0) {
            if (!empty($settings['polling_backlog_deferred'])) {
                $processed = max(0, (int)($settings['polling_last_backlog_processed'] ?? 0));
                $detail = $processed > 0
                    ? 'За последний запуск добавлено сообщений: ' . $processed . '. Остальное EasyChat перенесет автоматически.'
                    : 'Оставшиеся непрочитанные диалоги и недавняя история будут перенесены следующими запусками.';
                return $this->item('processing', 'Обработка сообщений', 'pending', 'Переносим диалоги', $detail, $ok_ts);
            }
            return $this->item('processing', 'Обработка сообщений', 'ok', 'Готово к приему', 'Очередь и сохранение сообщений работают.', $ok_ts);
        }
        return $this->item('processing', 'Обработка сообщений', 'pending', 'Ожидает первый запуск', 'Состояние появится после первой проверки MAX.');
    }

    private function summaryFromItems(string $status, array $items): array {
        if ($status !== 'active') {
            foreach ($items as $item) {
                if ((string)($item['key'] ?? '') === 'authorization' && (string)($item['state'] ?? '') === 'error') {
                    return $this->summary('error', (string)$item['title'], (string)$item['detail']);
                }
                if ((string)($item['key'] ?? '') === 'authorization' && (string)($item['state'] ?? '') === 'pending') {
                    return $this->summary('pending', (string)$item['title'], (string)$item['detail']);
                }
            }
            return $this->summary('disabled', 'Личный MAX выключен', 'Сессия не используется, пока канал выключен.');
        }
        foreach ($items as $item) {
            if ((string)$item['state'] === 'error') {
                return $this->summary('error', 'Требуется внимание', (string)$item['title'] . '. ' . (string)$item['detail']);
            }
        }
        foreach ($items as $item) {
            if ((string)$item['state'] === 'warning') {
                return $this->summary('warning', 'Работает с предупреждением', (string)$item['title'] . '. ' . (string)$item['detail']);
            }
        }
        foreach ($items as $item) {
            if ((string)$item['state'] === 'pending') {
                return $this->summary('pending', 'Завершаем проверку', 'EasyChat ждет ближайший запуск планировщика.');
            }
        }
        return $this->summary('ok', 'Личный MAX работает', 'Сессия, соединение, планировщик и обработка сообщений в норме.');
    }

    private function inboxStats(int $channel_id): array {
        if ($channel_id <= 0) {
            return ['count' => 0, 'oldest_at' => 0];
        }
        try {
            if (!$this->inbox) {
                $this->inbox = new MaxDurableInbox();
            }
            return $this->inbox->stats($channel_id);
        } catch (\Throwable $e) {
             
             
            return ['count' => 0, 'oldest_at' => 0];
        }
    }

    private function unavailableResult(array $channel, string $state, string $title, string $detail): array {
        $authorization = $this->item('authorization', 'Авторизация', $state, $title, $detail);
        return [
            'channel' => $channel,
            'settings' => $this->decodeJson((string)($channel['settings_json'] ?? '{}')),
            'generation' => 1,
            'summary' => $this->summary($state, $title, $detail),
            'items' => [
                $authorization,
                $this->item('api', 'MAX API', 'pending', 'Ожидает сессию', 'Проверка начнется после завершения обновления сессии.'),
                $this->item('cron', 'Cron', 'pending', 'Состояние неизвестно', 'Повторите проверку через несколько секунд.'),
                $this->item('processing', 'Обработка сообщений', 'pending', 'Ожидает проверку', 'Новые сообщения пока не проверялись.'),
            ],
            'session' => ['status' => 'unavailable', 'session_count' => 0, 'legacy_multiple' => false],
        ];
    }

    private function item(string $key, string $label, string $state, string $title, string $detail, int $timestamp = 0): array {
        $meta = $this->stateMeta($state);
        return [
            'key' => $key,
            'label' => $label,
            'state' => $state,
            'title' => $title,
            'detail' => $detail,
            'time' => $timestamp > 0 ? $this->relativeTime($timestamp) : '',
            'icon' => $meta['icon'],
            'class' => $meta['class'],
        ];
    }

    private function summary(string $state, string $title, string $detail): array {
        $meta = $this->stateMeta($state);
        return [
            'code' => $state,
            'badge_class' => $meta['badge'],
            'icon' => $meta['icon'],
            'title' => $title,
            'detail' => $detail,
        ];
    }

    private function stateMeta(string $state): array {
        $map = [
            'ok' => ['icon' => 'fa-check-circle', 'class' => 'is-ok', 'badge' => 'bg-success-subtle text-success border border-success-subtle'],
            'warning' => ['icon' => 'fa-exclamation-circle', 'class' => 'is-warning', 'badge' => 'bg-warning-subtle text-warning border border-warning-subtle'],
            'error' => ['icon' => 'fa-exclamation-triangle', 'class' => 'is-error', 'badge' => 'bg-danger-subtle text-danger border border-danger-subtle'],
            'pending' => ['icon' => 'fa-clock-o', 'class' => 'is-pending', 'badge' => 'bg-info-subtle text-info border border-info-subtle'],
            'disabled' => ['icon' => 'fa-pause-circle', 'class' => 'is-disabled', 'badge' => 'bg-light text-secondary border'],
        ];
        return $map[$state] ?? $map['pending'];
    }

    private function authErrorDetail(string $code): string {
        if ($code === 'session_store_unavailable') {
            return 'Проверьте права на защищенную папку storage.';
        }
        if ($code === 'error.limit.violate') {
            return 'MAX временно ограничил частые попытки. Подождите и повторите вход.';
        }
        return 'Повторите вход по QR или SMS. Старая попытка больше не используется.';
    }

    private function generationTimestamp(array $settings, string $prefix, int $generation): int {
        $stored_generation = (int)($settings[$prefix . '_generation'] ?? 0);
        if ($stored_generation !== $generation) {
            return 0;
        }
        return $this->timestamp($settings, $prefix);
    }

    private function timestamp(array $settings, string $prefix): int {
        $timestamp = max(0, (int)($settings[$prefix . '_ts'] ?? 0));
        if ($timestamp > 0) {
            return $timestamp;
        }
        $value = trim((string)($settings[$prefix . '_at'] ?? ''));
        $parsed = $value !== '' ? strtotime($value) : false;
        return $parsed !== false ? (int)$parsed : 0;
    }

    private function relativeTime(int $timestamp): string {
        $age = max(0, time() - $timestamp);
        if ($age < 60) {
            return $age . ' сек. назад';
        }
        if ($age < 3600) {
            return (int)floor($age / 60) . ' мин. назад';
        }
        return date('d.m.Y H:i', $timestamp);
    }

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