<?php

header('Access-Control-Allow-Origin: *');
header("Content-Type: application/json; charset=UTF-8");

$base = 'https://' . $_SERVER['SERVER_NAME'] . explode('?', $_SERVER['REQUEST_URI'])[0];

if ($_SERVER['REQUEST_METHOD'] !== 'GET' && $_SERVER['REQUEST_METHOD'] !== 'HEAD') {
    header('Status: 405');
    header('Content-Length: 56');
    header('Allow: GET, HEAD');
    echo "{\"error\":\"method not allowed\",\"allow\":[\"GET\",\"HEAD\"]}\n";
    exit;
}

function jenc($data): string {
    return json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
}

$info = $_SERVER['PATH_INFO'];
if ($info !== '') {
    $parts = explode(':', substr($info, 1), 2);
    if (sizeof($parts) !== 2) {
        $url = "https://elwig.at/organic/external/easy-cert/operators?idNr=" . substr($info, 1);
        $s = curl_init($url);
        curl_setopt($s, CURLOPT_RETURNTRANSFER, true);
        if (($json = curl_exec($s)) === false) {
            header('Status: 500');
            header('Content-Length: 34');
            echo "{\"error\":\"internal server error\"}\n";
            exit;
        }
        $json = json_decode($json);
        if ($json->{'totalCount'} !== 1) {
            header('Status: 404');
            header('Content-Length: 22');
            echo "{\"error\":\"not found\"}\n";
            exit;
        }
        header('Status: 303');
        header('Location: ./' . $json->{'data'}[0]->{'db'} . ':' . $json->{'data'}[0]->{'id'});
        exit;
    }

    $refDate = $_GET['referenceDate'] ?? null;
    if ($refDate !== null) {
        $refDate = explode('-', $refDate);
        $refDate = $refDate[2] . '.' . $refDate[1] . '.' . $refDate[0];
    }
    $url = "https://www.easy-cert.com/htm/suchresultat-detail.htm?sprache=de&db=" . urlencode($parts[0]) . "&id=" . urlencode(str_replace('-', '_', $parts[1])) . "&historyDate=" . urlencode($refDate);
    $s = curl_init($url);
    curl_setopt($s, CURLOPT_RETURNTRANSFER, true);
    if (($html = curl_exec($s)) === false) {
        header('Status: 500');
        header('Content-Length: 34');
        echo "{\"error\":\"internal server error\"}\n";
        exit;
    }

    $html = preg_replace('/<!--.*?-->/s', ' ', $html);
    preg_match_all('@<tr>\s*<th[^>]*>([^<]*)</th>\s*<td[^>]*>([^<]*)</td>\s*</tr>@', $html, $matches, PREG_SET_ORDER);

    $data = [];
    foreach ($matches as $m) {
        $data[$m[1]] = trim(html_entity_decode($m[2]));
        if ($data[$m[1]] === '') {
            $data[$m[1]] = null;
        }
    }
    $plzOrt = $data['PLZ / Ort'] ?? null;
    if ($plzOrt === null) {
        $postalCode = null;
        $city = null;
    } else {
        $p = explode(' ', $plzOrt, 2);
        $postalCode = trim($p[0]);
        $city = trim($p[1]);
    }

    if ($data['Name'] === null) {
        header('Status: 404');
        header('Content-Length: 22');
        echo "{\"error\":\"not found\"}\n";
        exit;
    }

    if (preg_match('@name="historydate_input" value="([^"]*)"@', $html, $matches) === 1) {
        $refDate = $matches[1];
        $refDate = explode('.', $refDate);
        $refDate = $refDate[2] . '-' . $refDate[1] . '-' . $refDate[0];
    } else {
        $refDate = null;
    }

    $certs = [];
    preg_match_all('@<tr>\s*<td nowrap>([^<]*)</td>\s*<td[^>]*>([^<]*)</td>\s*<td[^>]*>\s*([^<]*)\s*.*?</td>\s*<td [^\']*\'(https?://[^\']*)\'[^>]*>[^<]*</td>\s*</tr>@', $html, $matches, PREG_SET_ORDER);
    foreach ($matches as $m) {
        $certs[] = [
            'nr' => $m[1],
            'validUntil' => implode('-', array_reverse(explode('.', $m[2]))),
            'type' => $m[3] === '' ? null : $m[3],
            'pdfUrl' => str_replace('http://', 'https://', $m[4]),
        ];
    }

    $labels = [];
    preg_match_all('@<tr>\s*<td>([^<]*)</td>\s*<td[^>]*>([^<]*)</td>\s*<td[^>]*>\s*([^<]*)\s*.*?</td>\s*<td [^\']*\'(https?://[^\']*)\'[^>]*>[^<]*</td>\s*</tr>@', $html, $matches, PREG_SET_ORDER);
    foreach ($matches as $m) {
        $labels[] = [
            'nr' => $m[1],
            'validUntil' => implode('-', array_reverse(explode('.', $m[2]))),
            'type' => $m[3] === '' ? null : $m[3],
            'pdfUrl' => str_replace('http://', 'https://', $m[4]),
        ];
    }

    echo jenc([
        'db' => $parts[0],
        'id' => $parts[1],
        'idNr' => $data['ID-Nummer'] ?? null,
        'name' => $data['Name'],
        'address' => $data['Strasse'] ?? null,
        'postalCode' => $postalCode,
        'city' => $city,
        'countryCode' => $data['Land'] ?? null,
        'url' => $base,
        'originUrl' => $url,
        'referenceDate' => $refDate,
        'certificates' => $certs,
        'privateStandardApprovals' => $labels,
    ]);
    exit;
}

$search_url = null;
$url = null;
$query_id = null;
$timestamp = null;

$limit = $_GET['limit'] ?? null;
$offset = intval($_GET['offset'] ?? "0");
if ($limit === '') $limit = null;
if ($limit !== null) $limit = intval($limit);

if (isset($_GET['queryId'])) {
    $query_id = $_GET['queryId'];
    if ($cache = fopen('.cache.csv', 'r')) {
        while (($line = fgets($cache)) !== false) {
            $parts = explode(';', trim($line), 4);
            $timestamp = intval($parts[0]);
            if ($parts[1] !== $query_id) continue;
            $url = $parts[2];
            $search_url = $parts[3];
            break;
        }
        fclose($cache);
    }
} else {
    $country = $_GET['country'] ?? null;
    $postalCode = $_GET['postalCode'] ?? null;
    $name = $_GET['name'] ?? null;
    $idNr = $_GET['idNr'] ?? null;
    $renew = ($_GET['renew'] ?? 'false') === 'true';

    $search_url = "https://www.easy-cert.com/htm/suchergebnis.htm?suchtyp=einfach&CountryCode=$country&PostalCode=$postalCode&Name=$name&CustomerNumber=$idNr";

    if (!$renew && $cache = fopen('.cache.csv', 'r')) {
        while (($line = fgets($cache)) !== false) {
            $parts = explode(';', trim($line), 4);
            $timestamp = intval($parts[0]);
            if (time() - $timestamp > 60 * 30) continue;
            if ($parts[3] !== $search_url) continue;
            $url = $parts[2];
            $query_id = $parts[1];
            break;
        }
        fclose($cache);
    }
}

if ($url === null) {
    $timestamp = time();
    $s = curl_init($search_url);
    curl_setopt($s, CURLOPT_RETURNTRANSFER, true);
    $html = curl_exec($s);
    preg_match_all('/id="control_([^"]*)" value="([^"]*)"/', $html, $matches, PREG_SET_ORDER);
    $control = [];
    foreach ($matches as $m) {
        $control[$m[1]] = $m[2];
    }
    $query_id = $control['iniqueid'];
    $server_count = $control['countserver'];

    $lines = [];
    for ($i = 0; $i < 30; $i++) {
        sleep(1);
        $s = curl_init("https://www.easy-cert.com/_includes/search/result_items.php");
        curl_setopt($s, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($s, CURLOPT_HTTPHEADER, [
            'Referer: https://www.easy-cert.com/htm/suchergebnis.htm',
            'X-Requested-With: XMLHttpRequest',
            'X-USE: 1dfd3nsdv234njsdf923masddj123n12l31lg28gsdf2k34',
        ]);
        curl_setopt($s, CURLOPT_POSTFIELDS, "uniqueid=$query_id&countServer=$server_count");
        $json = json_decode(curl_exec($s));
        if ($json->{'count'} >= $server_count) {
            $url = "https://www.easy-cert.com/" . str_replace('../', '', $json->{'filename'});
            break;
        }
    }

    if ($url !== null)
        file_put_contents('.cache.csv', "$timestamp;$query_id;$url;$search_url\n", FILE_APPEND);
}

if ($url === null) {
    header('Status: 500');
    header('Content-Length: 34');
    echo "{\"error\":\"internal server error\"}\n";
    exit;
}

$sed = [
    's/^.*"searchresults":\[//',
    's/],.*$//',
    's/},{/},\n  {/g',
    '/^$/d',
    's/^/  /',
    's/}$/},/',
];
$replace = [
    '"DB":' => '"db":',
    '"Name":' => '"name":',
    '"PostalCode":' => '"postalCode":',
    '"Town":' => '"city":',
    '"CustomerNumber":' => '"idNr":',
    '"ID":' => '"id":',
    '"CountryCode":' => '"countryCode":',
    '"xx"' => 'null',
    '"XX"' => 'null',
    ':""' => ':null',
];
$replaceSed = array_map(fn($v, $k): string => "s/$k/$v/", $replace, array_keys($replace));

echo '{"searchUrl":' . jenc($search_url) .
    ',"queryId":' . jenc($query_id) .
    ',"rawFileUrl":' . jenc($url) .
    ',"timestamp":' . jenc(gmdate('Y-m-d\TH:i:s\Z', $timestamp)) .
    ',"limit":' . jenc($limit) .
    ',"offset":' . jenc($offset) . ",\"data\":[\n";

$fd_spec = [
    0 => ["pipe", "r"],  // stdin
    1 => ["pipe", "w"],  // stdout
    2 => ["pipe", "w"],  // stderr
    3 => ["pipe", "w"],  // line count
];
$offset++;
$process = proc_open(
    ['bash', '-c',
        "curl -s -N " . escapeshellarg($url) . " | " .    // fetch data (silent and unbuffered)
        "xxd -p | " .                                     // convert to hex stream
        "sed 's/7d2c7b/7d2c0a7b/g' | " .                  // roughly break up into lines (s/},{/},\n{/g)
        "xxd -r -p | " .                                  // convert to text stream
        "sed '" . implode(';', $sed) . "' | " .  // apply sed commands
        "tee >(wc -l 1>&3) | " .                          // copy stdout into wc and write result into fd 3
        "tail -n +$offset | " .                           // apply offset
        ($limit !== null ? " head -n $limit | " : "") .   // optionally apply limit
        "sed '" . implode(';', $replaceSed) . "' | " .  // replace strings in json
        "sed 's|{\\(\"db\":\"\\([^\"]*\\)\".*\"id\":\"\\([^\"]*\\)\".*\\)}|{\\1,\"url\":\"$base/\\2:\\3\"}|' | " .  // add "url"
        "sed '\$s/.$//'"],                                // remove last comma of last line
    $fd_spec,
    $pipes
);
fclose($pipes[0]);
fpassthru($pipes[1]);
fclose($pipes[1]);
$stderr = stream_get_contents($pipes[2]);
fclose($pipes[2]);
$count = intval(trim(stream_get_contents($pipes[3])));
fclose($pipes[3]);
$return_value = proc_close($process);

echo '],"totalCount":' . jenc($count) .  "}\n";
