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

use EasyChat\Library\Messenger\MessengerProviderInterface;

 
abstract class AbstractMarketplaceProvider implements MessengerProviderInterface, MarketplaceProviderInterface {
    protected $registry;
    protected $transport;

    public function __construct($registry = null, ?MarketplaceHttpTransport $transport = null) {
        $this->registry = $registry;
        $this->transport = $transport;
    }

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

    



    public function parseWebhook(array $payload): array {
        $event = is_array($payload['_marketplace_event'] ?? null) ? $payload['_marketplace_event'] : [];
        return $event;
    }

    public function markMarketplaceThreadRead(array $credentials, array $context): array {
        return ['success' => true, 'skipped' => true, 'reason' => 'read_receipt_not_supported'];
    }

    public function startMarketplaceConversation(array $credentials, array $context): array {
        return ['success' => false, 'error' => 'marketplace_start_not_supported'];
    }

    protected function credentials(string $token): array {
        $decoded = json_decode($token, true);
        return is_array($decoded) ? $decoded : [];
    }

    protected function safeString($value, int $limit = 1000): string {
        if (is_array($value) || is_object($value)) {
            return '';
        }
        return MarketplaceText::truncate(trim((string)$value), max(1, $limit));
    }

    protected function timestamp($value): int {
        return ProviderTimestamp::unix($value);
    }

    protected function isoDate($value): string {
         
         
        return ProviderTimestamp::isoUtc($value);
    }

    protected function textFromData($data): string {
        if (is_string($data)) {
            return trim($data);
        }
        if (!is_array($data)) {
            return '';
        }
        $parts = [];
        foreach ($data as $part) {
            if (is_string($part) && trim($part) !== '') {
                $parts[] = trim($part);
            } elseif (is_array($part)) {
                $text = $this->safeString($part['text'] ?? $part['value'] ?? '', 5000);
                if ($text !== '') {
                    $parts[] = $text;
                }
            }
        }
        return trim(implode("\n", $parts));
    }

    protected function sanitizedSnapshot(array $source, array $secret_keys = []): array {
        foreach ($secret_keys as $key) {
            unset($source[$key]);
        }
        return $this->limitDepth($source, 0);
    }

    private function limitDepth($value, int $depth) {
        if ($depth >= 5) {
            return '[truncated]';
        }
        if (!is_array($value)) {
            return is_string($value) ? MarketplaceText::truncate($value, 4000) : $value;
        }
        $result = [];
        $count = 0;
        foreach ($value as $key => $item) {
            if (++$count > 100) {
                $result['_truncated'] = true;
                break;
            }
            $result[$key] = $this->limitDepth($item, $depth + 1);
        }
        return $result;
    }

    protected function utf8Length($value): int {
        return MarketplaceText::length($value);
    }

    protected function failure(array $result, string $fallback): array {
        $failure = [
            'success' => false,
            'error' => (string)($result['error'] ?? $fallback),
            'http_code' => (int)($result['http_code'] ?? 0),
            'retryable' => !empty($result['retryable']),
        ];
        if (isset($result['retry_after_seconds'])) {
            $failure['retry_after_seconds'] = max(1, min(21600, (int)$result['retry_after_seconds']));
        }
        return $failure;
    }

    






    protected function writeFailure(array $result, string $fallback): array {
        $failure = $this->failure($result, $fallback);
        $http_code = (int)($failure['http_code'] ?? 0);
        $error = (string)($failure['error'] ?? '');
        $outcome_unknown = $http_code === 0
            || $http_code === 408
            || $http_code === 425
            || $http_code >= 500
            || $error === 'transport_failed';

        if ($outcome_unknown) {
            $failure['outcome_unknown'] = true;
            $failure['retryable'] = false;
        }
        return $failure;
    }
}
