<?php

declare(strict_types=1);

const SOURCE_FEED_URL = 'https://torebki-fabiola.pl/wp-content/uploads/woo-product-feed-pro/xml/05cgea7dmzuh29qasgcgllpwabbn0lut.xml';
const BRAND_NAME = 'Fabiola';
const GOOGLE_PRODUCT_CATEGORY = '3032';
const MPN_PREFIX = 'FAB-';
const GOOGLE_NAMESPACE_URI = 'http://base.google.com/ns/1.0';
const MPN_MAP_FILE = __DIR__ . '/zaufane-feed-mpn-map.json';

function fetchFeedXml(string $url): string
{
    $context = stream_context_create([
        'http' => [
            'method' => 'GET',
            'timeout' => 20,
            'ignore_errors' => true,
            'header' => "User-Agent: zaufane-feed-proxy/1.0\r\n",
        ],
    ]);

    $xml = @file_get_contents($url, false, $context);
    if ($xml !== false && trim($xml) !== '') {
        return $xml;
    }

    if (function_exists('curl_init')) {
        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_CONNECTTIMEOUT => 10,
            CURLOPT_TIMEOUT => 20,
            CURLOPT_USERAGENT => 'zaufane-feed-proxy/1.0',
        ]);
        $result = curl_exec($ch);
        $error = curl_error($ch);
        curl_close($ch);

        if (is_string($result) && trim($result) !== '') {
            return $result;
        }

        throw new RuntimeException('Nie udalo sie pobrac feedu (cURL): ' . $error);
    }

    throw new RuntimeException('Nie udalo sie pobrac feedu. Sprawdz allow_url_fopen lub cURL.');
}

function loadMpnMap(string $mapFile): array
{
    if (!is_file($mapFile)) {
        return [];
    }

    $json = @file_get_contents($mapFile);
    if (!is_string($json) || trim($json) === '') {
        return [];
    }

    $decoded = json_decode($json, true);
    return is_array($decoded) ? $decoded : [];
}

function saveMpnMap(string $mapFile, array $map): void
{
    $dir = dirname($mapFile);
    if (!is_dir($dir) && !@mkdir($dir, 0775, true) && !is_dir($dir)) {
        throw new RuntimeException('Nie mozna utworzyc katalogu mapy MPN: ' . $dir);
    }

    $handle = @fopen($mapFile, 'c+');
    if ($handle === false) {
        throw new RuntimeException('Nie mozna zapisac mapy MPN: ' . $mapFile);
    }

    if (!flock($handle, LOCK_EX)) {
        fclose($handle);
        throw new RuntimeException('Nie mozna zablokowac pliku mapy MPN.');
    }

    ftruncate($handle, 0);
    rewind($handle);
    fwrite($handle, json_encode($map, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
    fflush($handle);
    flock($handle, LOCK_UN);
    fclose($handle);
}

function normalizeTitleForMpn(string $title): string
{
    $title = trim($title);
    if ($title === '') {
        return 'produkt';
    }

    $transliterated = @iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $title);
    $title = is_string($transliterated) && $transliterated !== '' ? $transliterated : $title;

    $title = strtolower($title);
    $title = preg_replace('/[^a-z0-9]+/', '-', $title) ?? '';
    $title = trim($title, '-');

    if ($title === '') {
        return 'produkt';
    }

    return substr($title, 0, 48);
}

function getOrCreateMpn(array &$mpnMap, string $productId, string $title): string
{
    if (isset($mpnMap[$productId]) && is_string($mpnMap[$productId]) && $mpnMap[$productId] !== '') {
        return $mpnMap[$productId];
    }

    $base = normalizeTitleForMpn($title);
    $mpn = MPN_PREFIX . strtoupper($base . '-' . $productId);
    $mpnMap[$productId] = $mpn;

    return $mpn;
}

function setElementValue(DOMDocument $dom, DOMElement $parent, string $tagName, string $value): void
{
    $node = null;
    foreach ($parent->childNodes as $child) {
        if ($child instanceof DOMElement && $child->tagName === $tagName) {
            $node = $child;
            break;
        }
    }

    if (!$node) {
        $node = $dom->createElement($tagName);
        $parent->appendChild($node);
    }

    $node->nodeValue = $value;
}

function setGoogleElementValue(DOMDocument $dom, DOMElement $parent, string $localName, string $value): void
{
    $node = null;

    foreach ($parent->childNodes as $child) {
        if (!($child instanceof DOMElement)) {
            continue;
        }

        if ($child->localName === $localName && $child->namespaceURI === GOOGLE_NAMESPACE_URI) {
            $node = $child;
            break;
        }

        if ($child->tagName === 'g:' . $localName) {
            $node = $child;
            break;
        }
    }

    if (!$node) {
        $node = $dom->createElementNS(GOOGLE_NAMESPACE_URI, 'g:' . $localName);
        $parent->appendChild($node);
    }

    $node->nodeValue = $value;
}

try {
    $sourceXml = fetchFeedXml(SOURCE_FEED_URL);

    libxml_use_internal_errors(true);

    $dom = new DOMDocument('1.0', 'UTF-8');
    $dom->preserveWhiteSpace = false;
    $dom->formatOutput = false;

    if (!$dom->loadXML($sourceXml)) {
        throw new RuntimeException('Niepoprawny XML z feedu zrodlowego.');
    }

    $root = $dom->documentElement;
    if (!$root instanceof DOMElement) {
        throw new RuntimeException('Brak elementu glownego w XML.');
    }

    if (!$root->hasAttributeNS('http://www.w3.org/2000/xmlns/', 'g')) {
        $root->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:g', GOOGLE_NAMESPACE_URI);
    }

    $mpnMap = loadMpnMap(MPN_MAP_FILE);

    foreach ($dom->getElementsByTagName('product') as $productNode) {
        if (!($productNode instanceof DOMElement)) {
            continue;
        }

        $idNode = $productNode->getElementsByTagName('id')->item(0);
        $titleNode = $productNode->getElementsByTagName('title')->item(0);

        $productId = $idNode ? trim($idNode->textContent) : '';
        $title = $titleNode ? trim($titleNode->textContent) : '';

        if ($productId === '') {
            continue;
        }

        $mpn = getOrCreateMpn($mpnMap, $productId, $title);

        setElementValue($dom, $productNode, 'brand', BRAND_NAME);
        setGoogleElementValue($dom, $productNode, 'mpn', $mpn);
        setGoogleElementValue($dom, $productNode, 'google_product_category', GOOGLE_PRODUCT_CATEGORY);
    }

    saveMpnMap(MPN_MAP_FILE, $mpnMap);

    header('Content-Type: application/xml; charset=UTF-8');
    echo $dom->saveXML();
} catch (Throwable $e) {
    http_response_code(500);
    header('Content-Type: text/plain; charset=UTF-8');
    echo 'Blad generowania feedu: ' . $e->getMessage();
}

