<?php
namespace EasyChat\Library\Catalog;

use EasyChat\Library\Queue\QueueManager;








class CatalogPublicUrlService {

    const VERIFIED_TTL = 86400;
    const FAILED_TTL = 3600;

    private $registry;
    private $cms;
    private $cms_type;
    private $queue_manager;

    public function __construct($registry, $cms, string $cms_type) {
        $this->registry = $registry;
        $this->cms = $cms;
        $this->cms_type = preg_replace('/[^a-z0-9_-]/', '', strtolower(trim($cms_type)));
    }

    public function enrich(array $items, string $resource_type): array {
        $resource_type = $this->resourceType($resource_type);
        if ($resource_type === '' || !$items) {
            return $items;
        }

        if (method_exists($this->cms, 'resolvePublicUrls')) {
            try {
                $resolved = $this->cms->resolvePublicUrls($items, $resource_type);
                if (is_array($resolved)) {
                    $items = $resolved;
                }
            } catch (\Throwable $e) {
                 
                 
            }
        }

        $prepared = array();
        foreach ($items as $index => &$item) {
            if (!is_array($item)) {
                continue;
            }
            $source_url = trim((string)($item['link'] ?? $item['url'] ?? ''));
            if (!CatalogUrlPolicy::isSafeLink($source_url)) {
                continue;
            }
            $resource_id = mb_substr(trim((string)($item['id'] ?? $item['product_id'] ?? $item['page_id'] ?? '')), 0, 64, 'UTF-8');
            $label = trim((string)($item['name'] ?? $item['title'] ?? ''));
            $item['link'] = $source_url;
            $item['link_label'] = mb_substr($label, 0, 300, 'UTF-8');

            if ($resource_id === '' || !$this->isAbsoluteHttpUrl($source_url)) {
                continue;
            }
            $origin = $this->origin($source_url);
            if ($origin === '') {
                continue;
            }
            $cache_key = hash('sha256', $this->cms_type . "\n" . $resource_type . "\n" . $resource_id . "\n" . $origin);
            $prepared[$cache_key] = array(
                'index' => $index,
                'cache_key' => $cache_key,
                'resource_id' => $resource_id,
                'source_url' => $source_url,
                'source_hash' => hash('sha256', $source_url),
                'origin' => $origin,
            );
        }
        unset($item);

        if (!$prepared || !$this->registry || !function_exists('easychat_db_prefix')) {
            return $items;
        }

        try {
            $db = $this->registry->get('db');
            $prefix = easychat_db_prefix();
            $keys = array_map(function ($key) use ($db) {
                return "'" . $db->escape($key) . "'";
            }, array_keys($prepared));
            $result = $db->query(
                "SELECT cache_key, source_hash, canonical_url, status, expires_at
                 FROM `{$prefix}catalog_url_cache`
                 WHERE cache_key IN (" . implode(',', $keys) . ")"
            );

            $cached = array();
            foreach (($result->rows ?? array()) as $row) {
                $cached[(string)($row['cache_key'] ?? '')] = $row;
            }

            $now = time();
            $to_verify = array();
            foreach ($prepared as $cache_key => $entry) {
                $row = $cached[$cache_key] ?? array();
                $same_source = isset($row['source_hash']) && hash_equals((string)$row['source_hash'], $entry['source_hash']);
                $fresh = $same_source && (int)($row['expires_at'] ?? 0) > $now;
                $canonical = trim((string)($row['canonical_url'] ?? ''));
                if ($fresh && (string)($row['status'] ?? '') === 'verified'
                    && CatalogUrlPolicy::isSafeLink($canonical)
                    && $this->sameOrigin($canonical, $entry['origin'])) {
                    $items[$entry['index']]['link'] = $canonical;
                    if (isset($items[$entry['index']]['url'])) {
                        $items[$entry['index']]['url'] = $canonical;
                    }
                    continue;
                }
                if (!$fresh) {
                    $to_verify[] = $entry;
                }
            }

            if ($to_verify) {
                $this->rememberPending($db, $prefix, $resource_type, $to_verify, $now);
                $this->enqueueBatch($to_verify);
            }
        } catch (\Throwable $e) {
             
             
        }

        return $items;
    }

    private function rememberPending($db, string $prefix, string $resource_type, array $entries, int $now): void {
        $values = array();
        foreach (array_slice($entries, 0, 20) as $entry) {
            $values[] = "('" . $db->escape($entry['cache_key']) . "','" . $db->escape($this->cms_type)
                . "','" . $db->escape($resource_type) . "','" . $db->escape($entry['resource_id'])
                . "','" . $db->escape(hash('sha256', $entry['origin'])) . "','" . $db->escape($entry['source_url'])
                . "','" . $db->escape($entry['source_hash']) . "','','pending',0,'',{$now},{$now})";
        }
        if (!$values) {
            return;
        }
        $db->query(
            "INSERT INTO `{$prefix}catalog_url_cache`
             (cache_key,cms_type,resource_type,resource_id,origin_hash,source_url,source_hash,canonical_url,status,http_code,error_code,checked_at,expires_at)
             VALUES " . implode(',', $values) . "
             ON DUPLICATE KEY UPDATE
               status = IF(source_hash = VALUES(source_hash), status, 'pending'),
               expires_at = IF(source_hash = VALUES(source_hash), expires_at, VALUES(expires_at)),
               source_url = VALUES(source_url), source_hash = VALUES(source_hash)"
        );
    }

    private function enqueueBatch(array $entries): void {
        if ($this->queue_manager === null) {
            $this->queue_manager = new QueueManager($this->registry);
        }
        foreach (array_slice($entries, 0, 20) as $entry) {
            $payload_item = array(
                'cache_key' => $entry['cache_key'],
                'source_url' => $entry['source_url'],
                'source_hash' => $entry['source_hash'],
                'origin' => $entry['origin'],
            );
             
             
            $this->queue_manager->pushUnique(
                'catalog_url_verify',
                array('items' => array($payload_item)),
                'catalog_url_verify:' . substr(hash('sha256', $entry['cache_key'] . ':' . $entry['source_hash']), 0, 40),
                0,
                0
            );
        }
    }

    private function resourceType(string $value): string {
        $value = strtolower(trim($value));
        return in_array($value, array('product', 'page', 'category', 'information'), true) ? $value : '';
    }

    private function isAbsoluteHttpUrl(string $url): bool {
        $parts = @parse_url($url);
        return is_array($parts)
            && in_array(strtolower((string)($parts['scheme'] ?? '')), array('http', 'https'), true)
            && (string)($parts['host'] ?? '') !== '';
    }

    private function origin(string $url): string {
        $parts = @parse_url($url);
        if (!is_array($parts)) {
            return '';
        }
        $scheme = strtolower((string)($parts['scheme'] ?? ''));
        $host = strtolower((string)($parts['host'] ?? ''));
        if (!in_array($scheme, array('http', 'https'), true) || $host === '') {
            return '';
        }
        $port = isset($parts['port']) ? (int)$parts['port'] : ($scheme === 'https' ? 443 : 80);
        return $scheme . '://' . $host . ':' . $port;
    }

    private function sameOrigin(string $url, string $origin): bool {
        return hash_equals($origin, $this->origin($url));
    }
}
