<?php
declare(strict_types=1);
header('Content-Type: application/json; charset=utf-8');

/* ===================== Error/Env Setup ===================== */
error_reporting(E_ALL);
ini_set('display_errors', '0');
ini_set('log_errors', '1');
if (!ini_get('error_log')) {
    ini_set('error_log', __DIR__ . '/php-error.log');
}

/* ===================== Utilities ===================== */
function fail(string $msg, int $code = 400): void {
    http_response_code($code);
    echo json_encode(['error' => $msg], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT);
    exit;
}
function is_assoc(array $a): bool { return array_keys($a) !== range(0, count($a)-1); }
function to_abs_url(string $base, ?string $rel): ?string {
    if (!$rel) return null;
    if (preg_match('#^https?://#i', $rel)) return $rel;
    $p = parse_url($base);
    if (!$p || empty($p['scheme']) || empty($p['host'])) return $rel;
    $scheme = $p['scheme']; $host = $p['host'];
    $port = isset($p['port']) ? ':'.$p['port'] : '';
    $basePath = isset($p['path']) ? preg_replace('#/[^/]*$#', '/', $p['path']) : '/';
    if (substr($rel,0,1) === '/') $basePath = '';
    return "$scheme://$host$port" . $basePath . ltrim($rel,'/');
}
function fa_digits_to_en(string $s): string {
    $fa = ['۰','۱','۲','۳','۴','۵','۶','۷','۸','۹']; $en = ['0','1','2','3','4','5','6','7','8','9'];
    return str_replace($fa, $en, $s);
}
function push_attr(array &$bag, ?string $group, $name, $value, $unit = null): void {
    $name = trim((string)$name); $value = trim((string)$value); $unit = $unit ? trim((string)$unit) : null;
    if ($name === '' || $value === '') return;
    $bag[] = ['group'=>$group ?: null, 'name'=>$name, 'value'=>$value, 'unit'=>$unit];
}

/* ===================== Dependency Checks ===================== */
if (!function_exists('curl_init'))            fail('ماژول cURL روی سرور فعال نیست.', 500);
if (!class_exists('DOMDocument'))             fail('ماژول DOM/libxml روی سرور فعال نیست.', 500);
if (!function_exists('mb_detect_encoding'))   fail('ماژول mbstring روی سرور فعال نیست.', 500);

/* ===================== SSRF Guard (lenient) ===================== */
function host_is_public(string $host): bool {
    $ips = @gethostbynamel($host) ?: [];
    if (function_exists('dns_get_record')) {
        $aaaa = @dns_get_record($host, DNS_AAAA) ?: [];
        foreach ($aaaa as $rec) if (!empty($rec['ipv6'])) $ips[] = $rec['ipv6'];
    }
    if (!$ips) return true;
    foreach ($ips as $ip) {
        if (!filter_var($ip, FILTER_VALIDATE_IP)) continue;
        if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) === false) return false;
        if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
            if ($ip === '::1') return false;
            $bin = @inet_pton($ip);
            if ($bin !== false) {
                $hex = bin2hex($bin);
                if (preg_match('/^(fe8|fe9|fea|feb)/i', $hex)) return false;
                $first = substr($hex,0,2);
                if (preg_match('/^(fc|fd)/i', $first)) return false;
            }
        }
    }
    return true;
}

/* ===================== Input ===================== */
$url = $_GET['url'] ?? '';
if (!filter_var($url, FILTER_VALIDATE_URL) || !preg_match('#^https?://#i', $url)) fail('آدرس صفحه معتبر نیست یا وارد نشده است.');
$host = parse_url($url, PHP_URL_HOST);
if (!$host) fail('URL نامعتبر است.');
if (!host_is_public($host)) fail('دسترسی به این میزبان مجاز نیست.');

/* ===================== Fetch ===================== */
$ch = curl_init($url);
$headers = [
    'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8',
    'Accept-Language: fa-IR,fa;q=0.9,en;q=0.7',
    'Cache-Control: no-cache',
    'Pragma: no-cache',
    'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119 Safari/537.36'
];
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => $headers,
    CURLOPT_FOLLOWLOCATION => true,
    CURLOPT_MAXREDIRS      => 5,
    CURLOPT_CONNECTTIMEOUT => 10,
    CURLOPT_TIMEOUT        => 25,
    CURLOPT_FAILONERROR    => false,
    CURLOPT_ENCODING       => '',
    CURLOPT_PROTOCOLS      => CURLPROTO_HTTP | CURLPROTO_HTTPS,
    CURLOPT_REDIR_PROTOCOLS=> CURLPROTO_HTTP | CURLPROTO_HTTPS,
]);
$html = curl_exec($ch);
if ($html === false) fail('خطای شبکه: '.curl_error($ch), 502);
$httpCode     = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
$contentType  = curl_getinfo($ch, CURLINFO_CONTENT_TYPE) ?: '';
$finalUrl     = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL) ?: $url;
curl_close($ch);

if ($httpCode >= 400) fail("دریافت صفحه ناموفق بود (HTTP $httpCode)", 502);
if (!$html) fail('بدنهٔ صفحه خالی است.', 502);
if (!mb_detect_encoding($html, 'UTF-8', true)) $html = mb_convert_encoding($html, 'UTF-8', 'auto');

/* ===================== DOM & XPATH ===================== */
libxml_use_internal_errors(true);
$dom = new DOMDocument();
$dom->loadHTML($html);
$xp = new DOMXPath($dom);

/* ===================== __NEXT_DATA__ ===================== */
$data = null; $productData = null;
$nextNodes = $xp->query('//script[@id="__NEXT_DATA__" and @type="application/json"]');
if ($nextNodes->length) {
    $jsonText = $nextNodes->item(0)->textContent ?? '';
    $tmp = json_decode($jsonText, true);
    if (json_last_error() === JSON_ERROR_NONE && is_array($tmp)) {
        $data = $tmp;
        $pp = $data['props']['pageProps'] ?? [];
        foreach ([
            $pp['product'] ?? null,
            $pp['data']['product'] ?? null,
            $pp['initialState']['product'] ?? null,
            $pp['core']['product'] ?? null,
        ] as $cand) { if (is_array($cand) && !empty($cand)) { $productData = $cand; break; } }
    }
}

/* ===================== JSON-LD (Product & BreadcrumbList) ===================== */
$ldProduct = $ldBreadcrumb = null;
foreach ($xp->query('//script[@type="application/ld+json"]') as $node) {
    $txt = trim($node->textContent);
    $obj = json_decode($txt, true);
    if (json_last_error() !== JSON_ERROR_NONE) continue;
    $arr = is_assoc($obj ?? []) ? [$obj] : (is_array($obj) ? $obj : []);
    foreach ($arr as $o) {
        if (!is_array($o)) continue;
        if (($o['@type'] ?? '') === 'Product')        $ldProduct    = $o;
        if (($o['@type'] ?? '') === 'BreadcrumbList') $ldBreadcrumb = $o;
    }
}

/* ===================== Core fields ===================== */
$title        = $productData['title'] ?? ($ldProduct['name'] ?? '');
$descriptionH = $productData['descriptionHtml'] ?? ($productData['description'] ?? ($productData['shortDescription'] ?? null));
$descriptionT = $productData['description'] ?? '';
$price        = $productData['price'] ?? ($ldProduct['offers']['price'] ?? '');
$priceBefore  = $productData['primaryPrice'] ?? ($ldProduct['offers']['highPrice'] ?? null);
$currency     = $productData['currency'] ?? ($ldProduct['offers']['priceCurrency'] ?? '');
$availability = $productData['availability'] ?? ($productData['stockStatus'] ?? ($ldProduct['offers']['availability'] ?? ''));
$rating       = $productData['rating'] ?? ($ldProduct['aggregateRating']['ratingValue'] ?? null);
$reviewCount  = $productData['reviewCount'] ?? ($ldProduct['aggregateRating']['reviewCount'] ?? null);
$sku          = $productData['sku'] ?? ($ldProduct['sku'] ?? null);
$mpn          = $productData['mpn'] ?? ($ldProduct['mpn'] ?? null);
$productID    = $productData['productID'] ?? ($ldProduct['productID'] ?? null);
$brand        = $productData['brand']['name'] ?? ($ldProduct['brand']['name'] ?? ($ldProduct['brand'] ?? null));
$seller       = $productData['seller']['name'] ?? ($ldProduct['offers']['seller']['name'] ?? null);

/* ===================== Breadcrumb ===================== */
$breadcrumb = null;
if (!empty($data['props']['pageProps']['breadcrumbs'])) {
    $breadcrumb = implode(' > ', array_map(fn($b)=>trim((string)($b['title'] ?? '')), $data['props']['pageProps']['breadcrumbs']));
} elseif ($ldBreadcrumb && !empty($ldBreadcrumb['itemListElement'])) {
    $breadcrumb = implode(' > ', array_map(fn($it)=>trim((string)($it['name'] ?? '')), $ldBreadcrumb['itemListElement']));
} else {
    $crumbNodes = $xp->query('//*[@class="bs-breadcrumbs"]//*[self::a or self::span]');
    if ($crumbNodes->length) {
        $parts = [];
        foreach ($crumbNodes as $n) { $txt = trim($n->textContent); if ($txt !== '') $parts[] = $txt; }
        if ($parts) $breadcrumb = implode(' > ', $parts);
    }
}

/* ===================== Description (DOM fallback) ===================== */
if (!$descriptionH) {
    foreach ([
        '//*[@data-testid="product-description"]',
        '//*[@id="product-description" or contains(@class,"product-description")]',
        '//*[contains(@class,"bs-product__description") or contains(@class,"product__description")]',
        '//*[contains(@class,"description")][descendant::* or string-length(normalize-space())>0]'
    ] as $q) {
        $n = $xp->query($q);
        if ($n->length) { $descriptionH = $dom->saveHTML($n->item(0)); break; }
    }
}
$descriptionFull = $descriptionH
    ? trim(strip_tags($descriptionH, '<p><br><ul><ol><li><strong><em><b><i><h1><h2><h3>'))
    : ($descriptionT ?: '');

/* ===================== Features / Attributes ===================== */
$features = [];
$groups = $productData['attributeGroups'] ?? ($productData['core']['attributeGroups'] ?? null);
if (is_array($groups)) {
    foreach ($groups as $g) {
        $gname = $g['name'] ?? ($g['title'] ?? null);
        $attrs = $g['attributes'] ?? ($g['items'] ?? null);
        if (is_array($attrs)) {
            foreach ($attrs as $a) {
                $name = $a['name'] ?? ($a['title'] ?? null);
                $val  = $a['value'] ?? ($a['text'] ?? ($a['values'][0]['value'] ?? null));
                $unit = $a['unit'] ?? null;
                push_attr($features, $gname, $name, $val, $unit);
            }
        }
    }
}
if (empty($features) && !empty($productData['attributes']) && is_array($productData['attributes'])) {
    foreach ($productData['attributes'] as $a) {
        $gname = $a['group'] ?? null;
        $name  = $a['name'] ?? ($a['title'] ?? null);
        $val   = $a['value'] ?? ($a['values'][0]['value'] ?? null);
        $unit  = $a['unit'] ?? null;
        push_attr($features, $gname, $name, $val, $unit);
    }
}
if ($ldProduct && !empty($ldProduct['additionalProperty']) && is_array($ldProduct['additionalProperty'])) {
    foreach ($ldProduct['additionalProperty'] as $prop) {
        push_attr($features, null, $prop['name'] ?? null, $prop['value'] ?? null, $prop['unitCode'] ?? ($prop['unitText'] ?? null));
    }
}
if (empty($features)) {
    foreach ([
        '//table[contains(@class,"spec") or contains(@class,"feature") or contains(@class,"attribute")]/tbody/tr',
        '//*[self::ul or self::ol][contains(@class,"spec") or contains(@class,"feature") or contains(@class,"attribute")]/li',
        '//*[contains(@class,"spec") or contains(@class,"features") or contains(@class,"attributes")]//tr',
    ] as $q) {
        $rows = $xp->query($q);
        if (!$rows->length) continue;
        foreach ($rows as $row) {
            if (strtolower($row->nodeName)==='tr') {
                $ths = $row->getElementsByTagName('th'); $tds = $row->getElementsByTagName('td');
                if ($ths->length && $tds->length) push_attr($features, null, $ths->item(0)->textContent, $tds->item(0)->textContent);
                elseif ($tds->length>=2)          push_attr($features, null, $tds->item(0)->textContent, $tds->item(1)->textContent);
            } else {
                $txt = trim($row->textContent);
                if (strpos($txt, ':')!==false) { [$n,$v] = array_map('trim', explode(':',$txt,2)); push_attr($features, null, $n, $v); }
            }
        }
        if (!empty($features)) break;
    }
}
$features_text = !empty($features)
    ? fa_digits_to_en(implode(' | ', array_map(function($f){
        $lbl = trim($f['name']); $val = trim($f['value'] . ($f['unit'] ? " {$f['unit']}" : ''));
        return ($f['group'] ? "{$f['group']} – " : '') . "{$lbl}: {$val}";
    }, $features)))
    : null;

/* ===================== Images (CDN کاربران باسلام) ===================== */
/*
  فقط URLهایی که روی statics.basalam.com و مسیر /public-xx/(users|shops)/ هستند نگه داشته می‌شوند.
  سیاست انتخاب:
    1) نسخهٔ «اصلی» (بدون پسوند _WxH[xQ].ext)  => Rank 1
    2) «استاندارد» = عرض >= 1024               => Rank 2
    3) در غیر اینصورت، بزرگ‌ترین رزولوشن      => Rank 3
*/
function img_ext_ok(string $url): bool {
    $path = strtolower(parse_url($url, PHP_URL_PATH) ?? '');
    return (bool)preg_match('#\.(jpe?g|png|webp|avif|gif)(?:_[0-9]+x[0-9]+(?:x[0-9]+)?\.(?:jpe?g|png|webp|avif|gif))?$#i', $path)
        || (bool)preg_match('#\.(jpe?g|png|webp|avif|gif)$#i', $path);
}
function img_is_junk(string $url): bool {
    $url = strtolower($url);
    if (strpos($url, 'data:') === 0) return true;
    $path = parse_url($url, PHP_URL_PATH) ?? '';
    if (preg_match('#\.svg$#i', $path)) return true;
    $bad = ['logo','logotype','favicon','sprite','icon','placeholder','banner','header','footer','payment','star','rating','share','arrow','close','default','avatar','emoji','/_next/image','/icons/','/sprites/','/static/','/img/'];
    foreach ($bad as $kw) { if (strpos($path, $kw) !== false) return true; }
    return false;
}
function img_users_cdn_allowed(string $url): bool {
    $host = strtolower(parse_url($url, PHP_URL_HOST) ?? '');
    $path = strtolower(parse_url($url, PHP_URL_PATH) ?? '');
    if ($host !== 'statics.basalam.com') return false;
    return (bool)preg_match('#^/public-\d+/(users|shops)/#', $path);
}
function img_parse_suffix_size(string $url): ?array {
    $path = parse_url($url, PHP_URL_PATH) ?? '';
    if (preg_match('#_(\d+)[xX](\d+)(?:[xX](\d+))?\.(jpe?g|png|webp|avif|gif)$#i', $path, $m)) {
        return [intval($m[1]), intval($m[2]), isset($m[3]) ? intval($m[3]) : null];
    }
    return null;
}
function img_base_without_size(string $url): string {
    $p = parse_url($url);
    $scheme = $p['scheme'] ?? 'https';
    $host   = $p['host']   ?? '';
    $path   = $p['path']   ?? '';
    if (preg_match('#_(\d+)[xX](\d+)(?:[xX](\d+))?\.(jpe?g|png|webp|avif|gif)$#i', $path)) {
        $path = preg_replace('#_(\d+)[xX](\d+)(?:[xX](\d+))?\.(jpe?g|png|webp|avif|gif)$#i', '.$4', $path);
    }
    return $scheme.'://'.$host.$path;
}
function img_rank_for_users_cdn(string $url): array {
    $size = img_parse_suffix_size($url);
    if ($size === null) return [1, PHP_INT_MAX]; // نسخهٔ اصلی
    [$w,$h] = $size;
    if ($w >= 1024) return [2, $w*$h];          // استاندارد
    return [3, $w*$h];                           // سایر
}

$rawImages = [];
$pushRaw = function($u) use (&$rawImages, $finalUrl) {
    if (!$u) return;
    $abs = to_abs_url($finalUrl, $u);
    if ($abs) $rawImages[] = $abs;
};

/* JSON محصول */
if (is_array($productData)) {
    foreach (['gallery','photos','images'] as $k) {
        if (!empty($productData[$k]) && is_array($productData[$k])) {
            foreach ($productData[$k] as $img) { $pushRaw($img['url'] ?? $img['src'] ?? null); }
        }
    }
    if (!empty($productData['image']['url'])) $pushRaw($productData['image']['url']);
}

/* JSON-LD Product image[] — اولویت contentUrl سپس url/@id */
if ($ldProduct && !empty($ldProduct['image'])) {
    foreach ((array)$ldProduct['image'] as $img) {
        $val = is_array($img) ? ($img['contentUrl'] ?? $img['url'] ?? ($img['@id'] ?? null)) : $img;
        $pushRaw($val);
    }
}

/* OG:image (تصویر شاخص) */
foreach ($xp->query('//meta[translate(@property,"ABCDEFGHIJKLMNOPQRSTUVWXYZ","abcdefghijklmnopqrstuvwxyz")="og:image"]/@content') as $og) {
    $pushRaw($og->nodeValue);
}

/* DOM گالری (bs-light-carousel و ...). فقط اگر از selector تصویر جدید گرفتیم، break */
foreach ([
    '//*[@data-testid="product-gallery"]//img',
    '//*[contains(@class,"bs-light-carousel")]//img',
    '//*[contains(@class,"product") and contains(@class,"gallery")]//img',
    '//*[@id="product-gallery"]//img',
    '//*[@id="product"]//img',
] as $q) {
    $before = count($rawImages);
    $nodes = $xp->query($q);
    if ($nodes->length) {
        foreach ($nodes as $img) {
            $pushRaw($img->getAttribute('src'));
            $pushRaw($img->getAttribute('data-src'));
            $srcset = $img->getAttribute('srcset');
            if ($srcset) {
                foreach (preg_split('/\s*,\s*/', $srcset) as $part) {
                    $u = trim(preg_split('/\s+/', $part)[0] ?? '');
                    if ($u) $pushRaw($u);
                }
            }
        }
    }
    if (count($rawImages) > $before) break;
}

/* فیلتر: فقط users/shops روی statics.basalam.com + حذف junk + فرمت‌های معتبر */
$filtered = [];
foreach ($rawImages as $u) {
    if (!img_ext_ok($u)) continue;
    if (img_is_junk($u)) continue;
    if (!img_users_cdn_allowed($u)) continue;
    $filtered[] = $u;
}

/* dedupe & pick best (یک URL به ازای هر base) */
$best = []; // base => ['url'=>..., 'rank'=>[class,res]]
foreach ($filtered as $u) {
    $base = img_base_without_size($u);
    [$cls,$res] = img_rank_for_users_cdn($u);
    if (!isset($best[$base]) || $cls < $best[$base]['rank'][0] || ($cls === $best[$base]['rank'][0] && $res > $best[$base]['rank'][1])) {
        $best[$base] = ['url'=>$u, 'rank'=>[$cls,$res]];
    }
}
$images = array_values(array_map(fn($x)=>$x['url'], $best));

/* ===================== Output ===================== */
$out = [
    'title'                 => $title ?: null,
    'description_html'      => $descriptionH ?: null,
    'description_fulltext'  => $descriptionFull ?: null,
    'price'                 => $price ?: null,
    'price_before'          => $priceBefore ?: null,
    'currency'              => $currency ?: null,
    'availability'          => $availability ?: null,
    'rating'                => $rating ?: null,
    'reviewCount'           => $reviewCount ?: null,
    'sku'                   => $sku ?: null,
    'mpn'                   => $mpn ?: null,
    'productID'             => $productID ?: null,
    'brand'                 => $brand ?: null,
    'seller'                => $seller ?: null,
    'breadcrumb'            => $breadcrumb ?: null,
    'features'              => $features,
    'features_text'         => $features_text,
    'images'                => $images,
    'source'                => [
        'url'         => $url,
        'finalUrl'    => $finalUrl,
        'httpCode'    => $httpCode,
        'contentType' => $contentType
    ]
];

echo json_encode($out, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT);
