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

use EasyChat\Library\Messenger\OzonProvider;
use EasyChat\Library\Messenger\ProviderRegistry;
use EasyChat\Library\Messenger\YandexMarketProvider;
use EasyChat\Library\Queue\QueueManager;
use EasyChat\Model\Marketplace as MarketplaceModel;
use EasyChat\Model\Messenger as MessengerModel;
use EasyChat\Model\Setting;







class MarketplaceAccountService {
    private $registry;

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

    public function connect(string $provider_code, array $input, int $channel_id = 0): array {
        $provider_code = $this->normalizeProvider($provider_code);
        $provider = ProviderRegistry::get($provider_code, $this->registry);
        if (!$provider instanceof MarketplaceProviderInterface) {
            return ['success' => false, 'error' => 'marketplace_provider_unavailable'];
        }

         
         
         
        if ((string)(new Setting($this->registry))->get('chat_install_secret', '') === '') {
            return ['success' => false, 'error' => 'install_secret_missing'];
        }

        $capabilities = $provider->marketplaceCapabilities();
        $secret_fields = is_array($capabilities['secret_fields'] ?? null)
            ? array_values(array_filter(array_map('strval', $capabilities['secret_fields'])))
            : [];
        $messenger = new MessengerModel($this->registry);
        $existing = $channel_id > 0 ? $messenger->getChannelById($channel_id) : [];
        if ($existing && (string)($existing['provider'] ?? '') !== $provider_code) {
            return ['success' => false, 'error' => 'marketplace_account_provider_mismatch'];
        }
        $reactivating = $existing && (string)($existing['status'] ?? '') !== 'active';

        $credentials = [];
        if ($existing) {
            $stored = $this->decode((string)($existing['credentials_json'] ?? ''));
            $credentials = (new MarketplaceCredentialsVault($this->registry))->open($stored, $secret_fields);
        }
        foreach ($this->credentialFields($provider_code) as $field) {
            if (!array_key_exists($field, $input)) continue;
            $value = trim((string)$input[$field]);
             
            if ($value !== '' || !in_array($field, $secret_fields, true)) {
                $credentials[$field] = $value;
            }
        }

        $validation = $provider->validateMarketplaceCredentials($credentials);
        if (empty($validation['success'])) {
            return [
                'success' => false,
                'error' => (string)($validation['error'] ?? 'marketplace_credentials_invalid'),
                'http_code' => (int)($validation['http_code'] ?? 0),
            ];
        }

        $account = is_array($validation['account'] ?? null) ? $validation['account'] : [];
        $external_account_id = MarketplaceText::truncate(trim((string)($account['id'] ?? '')), 128);
        if ($external_account_id === '') {
            return ['success' => false, 'error' => 'marketplace_account_identity_missing'];
        }
        $resolved_credentials = is_array($validation['credential_values'] ?? null)
            ? $validation['credential_values']
            : [];
        if (isset($resolved_credentials['business_id'])
            && hash_equals($external_account_id, trim((string)$resolved_credentials['business_id']))) {
             
             
            $credentials['business_id'] = $external_account_id;
        }
        if ($existing && !hash_equals((string)($existing['external_account_id'] ?? ''), $external_account_id)) {
            return ['success' => false, 'error' => 'marketplace_account_identity_mismatch'];
        }
        $channel = $messenger->ensureMarketplaceChannel(
            $provider_code,
            $external_account_id,
            (string)($account['name'] ?? strtoupper($provider_code)),
            (string)($capabilities['auth_type'] ?? 'token')
        );
        if (!$channel || ($existing && (int)$channel['channel_id'] !== (int)$existing['channel_id'])) {
            return ['success' => false, 'error' => 'marketplace_account_conflict'];
        }

        $sealed = (new MarketplaceCredentialsVault($this->registry))->seal($credentials, $secret_fields);
        $effective_capabilities = is_array($validation['capabilities'] ?? null)
            ? $validation['capabilities']
            : $capabilities;
        $settings = $existing
            ? $this->decode((string)($existing['settings_json'] ?? ''))
            : [];
        if ($provider_code === YandexMarketProvider::PROVIDER) {
            $settings['ai_auto_reply'] = array_key_exists('ai_auto_reply', $input)
                ? !empty($input['ai_auto_reply'])
                : !empty($settings['ai_auto_reply']);
        }
        $messenger->updateChannel((int)$channel['channel_id'], [
            'title' => MarketplaceText::truncate(trim((string)($account['name'] ?? strtoupper($provider_code))), 128),
            'external_account_id' => $external_account_id,
            'auth_type' => (string)($capabilities['auth_type'] ?? 'token'),
            'status' => 'active',
            'credentials_json' => $this->encode($sealed),
            'capabilities_json' => $this->encode($effective_capabilities),
            'settings_json' => $this->encode($settings),
            'last_error' => '',
        ]);

        $marketplace = new MarketplaceModel($this->registry);
        $stream_access = is_array($effective_capabilities['stream_access'] ?? null)
            ? $effective_capabilities['stream_access']
            : [];
        $streams = array_keys(is_array($capabilities['streams'] ?? null) ? $capabilities['streams'] : []);
        $marketplace->ensureStreams((int)$channel['channel_id'], $streams, true);
        foreach ($streams as $stream) {
            if (($stream_access[$stream]['available'] ?? null) === false) {
                $marketplace->setStreamStatus((int)$channel['channel_id'], (string)$stream, false);
            } elseif ($reactivating) {
                 
                 
                 
                 
                $marketplace->setStreamStatus((int)$channel['channel_id'], (string)$stream, true);
            }
        }

        $webhook = ['success' => true, 'mode' => 'polling', 'webhook_supported' => false];
        if ($provider_code === OzonProvider::PROVIDER) {
            $fresh = $messenger->getChannelById((int)$channel['channel_id']);
            $webhook = $provider->syncWebhook(
                $fresh,
                $this->encode($credentials),
                $this->ozonWebhookUrl($fresh),
                ''
            );
            $messenger->updateChannel((int)$channel['channel_id'], [
                 
                'webhook_synced_at' => !empty($webhook['success']) ? date('Y-m-d H:i:s') : null,
                'last_error' => !empty($webhook['success']) ? '' : (string)($webhook['error'] ?? 'notification_setup_failed'),
            ]);
        } elseif ($provider_code === YandexMarketProvider::PROVIDER) {
            $fresh = $messenger->getChannelById((int)$channel['channel_id']);
            $webhook = $provider->syncWebhook(
                $fresh,
                $this->encode($credentials),
                $this->marketplaceWebhookUrl($fresh),
                ''
            );
        }

        $this->queueStreams((int)$channel['channel_id']);
        return [
            'success' => true,
            'account' => $this->publicAccount($messenger->getChannelById((int)$channel['channel_id'])),
            'key_health' => $provider_code === OzonProvider::PROVIDER
                ? MarketplaceAdminPresenter::ozonKeyHealth((string)($effective_capabilities['key_expires_at'] ?? ''))
                : [],
            'diagnostics' => is_array($validation['diagnostics'] ?? null) ? $validation['diagnostics'] : [],
            'webhook' => $webhook,
        ];
    }

    public function disconnect(int $channel_id): array {
        $messenger = new MessengerModel($this->registry);
        $channel = $messenger->getChannelById($channel_id);
        if (!$this->isMarketplaceChannel($channel)) {
            return ['success' => false, 'error' => 'marketplace_account_not_found'];
        }
        $cleanup = ['success' => true, 'skipped' => true];
        if ((string)($channel['provider'] ?? '') === OzonProvider::PROVIDER) {
            try {
                $provider = ProviderRegistry::get(OzonProvider::PROVIDER, $this->registry);
                $capabilities = $provider instanceof MarketplaceProviderInterface ? $provider->marketplaceCapabilities() : [];
                $credentials = (new MarketplaceCredentialsVault($this->registry))->open(
                    $this->decode((string)($channel['credentials_json'] ?? '')),
                    is_array($capabilities['secret_fields'] ?? null) ? $capabilities['secret_fields'] : []
                );
                if ($provider instanceof OzonProvider) {
                    $cleanup = $provider->removeWebhook($credentials, $this->ozonWebhookUrl($channel));
                }
            } catch (\Throwable $e) {
                 
                 
                $cleanup = ['success' => false, 'error' => 'notification_cleanup_failed'];
            }
        }
        $marketplace = new MarketplaceModel($this->registry);
        foreach ($marketplace->listStreams($channel_id) as $stream) {
            $marketplace->setStreamStatus($channel_id, (string)$stream['stream'], false);
        }
        $messenger->updateChannel($channel_id, [
            'status' => 'disabled',
            'credentials_json' => '',
            'webhook_synced_at' => null,
            'last_error' => '',
        ]);
        return ['success' => true, 'webhook_cleanup' => $cleanup];
    }

    public function setStreamStatus(int $channel_id, string $stream, bool $enabled): array {
        $channel = (new MessengerModel($this->registry))->getChannelById($channel_id);
        if (!$this->isMarketplaceChannel($channel) || (string)($channel['status'] ?? '') !== 'active') {
            return ['success' => false, 'error' => 'marketplace_account_inactive'];
        }
        $stream = MarketplaceStream::normalize($stream);
        if ($stream === '') {
            return ['success' => false, 'error' => 'marketplace_stream_unknown'];
        }
        $capabilities = $this->decode((string)($channel['capabilities_json'] ?? ''));
        if ($enabled && ($capabilities['stream_access'][$stream]['available'] ?? null) === false) {
            return ['success' => false, 'error' => 'marketplace_stream_permission_missing'];
        }
        $model = new MarketplaceModel($this->registry);
        $model->setStreamStatus($channel_id, $stream, $enabled);
        if ($enabled) $this->queueStreams($channel_id, $stream);
        return ['success' => true];
    }

    public function syncNow(int $channel_id, string $stream = ''): array {
        $channel = (new MessengerModel($this->registry))->getChannelById($channel_id);
        if (!$this->isMarketplaceChannel($channel) || (string)($channel['status'] ?? '') !== 'active') {
            return ['success' => false, 'error' => 'marketplace_account_inactive'];
        }
        $requested_stream = trim($stream);
        $normalized_stream = MarketplaceStream::normalize($requested_stream);
        if ($requested_stream !== '' && $normalized_stream === '') {
            return ['success' => false, 'error' => 'marketplace_stream_unknown'];
        }
        return ['success' => true, 'queued' => $this->queueStreams($channel_id, $normalized_stream)];
    }

     
    public function setOptions(int $channel_id, array $input): array {
        $messenger = new MessengerModel($this->registry);
        $channel = $messenger->getChannelById($channel_id);
        if (!$this->isMarketplaceChannel($channel)
            || (string)($channel['provider'] ?? '') !== YandexMarketProvider::PROVIDER
            || (string)($channel['status'] ?? '') !== 'active') {
            return ['success' => false, 'error' => 'marketplace_account_inactive'];
        }
        $settings = $this->decode((string)($channel['settings_json'] ?? ''));
        foreach (['ai_auto_reply'] as $key) {
            if (array_key_exists($key, $input)) {
                $settings[$key] = !empty($input[$key]);
            }
        }
        $messenger->updateChannel($channel_id, ['settings_json' => $this->encode($settings)]);
        return [
            'success' => true,
            'options' => [
                'ai_auto_reply' => !empty($settings['ai_auto_reply']),
            ],
        ];
    }

    private function queueStreams(int $channel_id, string $only_stream = ''): int {
        $model = new MarketplaceModel($this->registry);
        $queue = new QueueManager($this->registry);
        $queued = 0;
        foreach ($model->listStreams($channel_id) as $stream) {
            if ((string)($stream['status'] ?? '') !== 'enabled') continue;
            if ($only_stream !== '' && (string)$stream['stream'] !== $only_stream) continue;
            $model->wakeStream($channel_id, (string)$stream['stream']);
            $stream_id = (int)($stream['stream_id'] ?? 0);
            if ($stream_id <= 0) continue;
            $queue->pushUnique(
                'messenger_marketplace_sync',
                ['stream_id' => $stream_id],
                'marketplace_stream_' . $stream_id,
                0,
                (string)$stream['stream'] === MarketplaceStream::BUYER_CHAT ? 8 : 4
            );
            $queued++;
        }
        return $queued;
    }

    private function publicAccount(array $channel): array {
        $settings = $this->decode((string)($channel['settings_json'] ?? ''));
        return [
            'channel_id' => (int)($channel['channel_id'] ?? 0),
            'provider' => (string)($channel['provider'] ?? ''),
            'external_account_id' => (string)($channel['external_account_id'] ?? ''),
            'title' => (string)($channel['title'] ?? ''),
            'status' => (string)($channel['status'] ?? ''),
            'last_error' => (string)($channel['last_error'] ?? ''),
            'webhook_synced_at' => (string)($channel['webhook_synced_at'] ?? ''),
            'webhook_url' => (string)($channel['provider'] ?? '') === YandexMarketProvider::PROVIDER
                ? $this->marketplaceWebhookUrl($channel)
                : '',
            'options' => [
                'ai_auto_reply' => !empty($settings['ai_auto_reply']),
            ],
        ];
    }

    private function credentialFields(string $provider): array {
        return MarketplaceProviderCatalog::credentialFields($provider);
    }

    private function ozonWebhookUrl(array $channel): string {
        $public_id = (string)($channel['public_id'] ?? '');
        $install_secret = trim((string)(new Setting($this->registry))->get('chat_install_secret', ''));
        if ($public_id === '' || $install_secret === '') {
            return '';
        }
        $signature = hash_hmac('sha256', "easychat:ozon-webhook:v1\0" . $public_id, $install_secret);
        return rtrim((string)HTTP_SERVER, '/') . '/index.php?route=messenger/webhook&provider=ozon&id='
            . rawurlencode($public_id) . '&signature=' . rawurlencode($signature);
    }

    private function marketplaceWebhookUrl(array $channel): string {
        return rtrim((string)HTTP_SERVER, '/') . '/index.php?route=messenger/webhook&provider='
            . rawurlencode((string)($channel['provider'] ?? ''))
            . '&id=' . rawurlencode((string)($channel['public_id'] ?? ''));
    }

    private function isMarketplaceChannel($channel): bool {
        return is_array($channel) && MarketplaceProviderCatalog::has((string)($channel['provider'] ?? ''));
    }

    private function normalizeProvider(string $provider): string {
        return MarketplaceProviderCatalog::normalize($provider);
    }

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

    private function encode(array $value): string {
        $json = json_encode($value, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
        return is_string($json) ? $json : '{}';
    }
}
