<?php

require "../.php/pdf.php";

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

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);
}

function jget($url): array | null {
    $s = curl_init($url);
    curl_setopt($s, CURLOPT_RETURNTRANSFER, true);
    if (($json = curl_exec($s)) === false) {
        return null;
    }
    return json_decode($json, true);
}

function pdf_fetch($url): array | null {
    $s = curl_init("https://elwig.at/organic/pdf?format=json&url=" . urlencode($url));
    curl_setopt($s, CURLOPT_RETURNTRANSFER, true);
    if (($json = curl_exec($s)) === false) {
        return null;
    }
    return json_decode($json, true);
}

function update_local(string $ooId, array $new): bool {
    $existed = file_exists(".ids/$ooId.txt");
    if (!($file = fopen(".ids/$ooId.txt", 'c+')))
        return !$existed;
    $data = [];
    while (($line = fgets($file)) !== false) {
        [$k,$v] = explode(':', trim($line), 2);
        $data[$k] = $v;
    }
    foreach ($new as $k => $v) {
        if ($v !== null)
            $data[$k] = $v;
    }
    fseek($file, 0);
    ftruncate($file, 0);
    foreach ($data as $k => $v) {
        fwrite($file, "$k:$v\n");
    }
    fclose($file);
    return !$existed;
}

function find_local(string $anyId): string | null {
    $found = [];
    foreach (scandir('.ids/') as $file) {
        if (!str_ends_with($file, '.txt')) continue;
        $data = file_get_contents(".ids/$file");
        if (str_contains($data, "\n$anyId\n"))
            $found[] = substr($file, 0, strlen($file) - 4);
    }
    return sizeof($found) === 1 ? $found[0] : null;
}

function update_cache(string $country, string $postalCode): void {
    $anyNew = false;
    $traces = jget("https://webgate.ec.europa.eu/tracesnt/directory/publication/organic-operator/for/query?countryCode=$country&operatorPostalCode=$postalCode&sort=issuedOn");
    foreach ($traces as $op) {
        // traces
        $ooId = $op['operatorIdentifier'];
        $name = $op['operator']['name'];
        $address = $op['operator']['address']['street']['value'];
        $cityPostalCode = $op['operator']['address']['cityReference']['postalCode'];
        $cityName = $op['operator']['address']['cityReference']['name'];
        $new = update_local($ooId, ['plz' => $postalCode, 'name' => "$name|$address|$cityPostalCode $cityName"]);
        $anyNew = $anyNew || $new;
    }
    if (!$anyNew) return;

    $m = curl_multi_init();
    $requests = [];
    foreach (['easy-cert', 'bioc', 'bioqs', 'lkv'] as $api) {
        $s = curl_init("https://elwig.at/organic/external/$api/operators?country=$country&postalCode=$postalCode");
        $requests[] = $s;
        curl_setopt($s, CURLOPT_RETURNTRANSFER, true);
        curl_multi_add_handle($m, $s);
    }

    $running = 1;
    do {
        curl_multi_exec($m, $running);
        if ($running) usleep(250_000);
    } while ($running);
    foreach ($requests as $r) {
        curl_multi_remove_handle($m, $r);
    }
    curl_multi_close($m);
    $data = [];
    foreach ($requests as $s) {
        if (($json = curl_multi_getcontent($s)) === null) {
            header('Status: 500');
            header('Content-Length: 34');
            echo "{\"error\":\"internal server error\"}\n";
            exit;
        }
        $data[] = json_decode($json, true)['data'];
    }

    foreach ($data[0] as $op) {
        // easy-cert
        $ooId = find_local("easy-cert:$op[db]:$op[id]");
        $lfbisNr = null;
        if ($ooId === null && ($opDetails = jget($op['url'])) !== null) {
            foreach ($opDetails['certificates'] as $cert) {
                if (preg_match("/\.([0-9]{3}-[0-9]{7})\./", $cert['nr'], $matches) === 1) {
                    $ooId = $matches[1];
                }
            }
            if ($ooId === null || $lfbisNr === null) {
                foreach ($opDetails['certificates'] as $cert) {
                    if ($cert['pdfUrl'] === null) continue;
                    $pdfDetails = pdf_fetch($cert['pdfUrl']);
                    if (isset($pdfDetails['operator']['lfbisNr'])) $lfbisNr = $pdfDetails['operator']['lfbisNr'];
                    if (!isset($pdfDetails['id'])) continue;
                    if (preg_match("/\.([0-9]{3}-[0-9]{7})\./", $pdfDetails['id'], $matches) === 1) {
                        $ooId = $matches[1];
                    }
                }
            }
        }
        if ($ooId === null)
            continue;
        update_local($ooId, ['plz' => $postalCode, 'lfbis' => $lfbisNr, 'easy-cert' => "$op[db]:$op[id]"]);
    }
    foreach ($data[1] as $op) {
        // bioc
        $ooId = find_local("bioc:$op[id]");
        if ($ooId === null && ($opDetails = jget($op['url'])) !== null) {
            foreach ($opDetails['certificates'] as $cert) {
                if (preg_match("/\.([0-9]{3}-[0-9]{7})\./", $cert['nr'], $matches) === 1) {
                    $ooId = $matches[1];
                }
            }
            if ($ooId === null) {
                foreach ($opDetails['certificates'] as $cert) {
                    if ($cert['pdfUrl'] === null) continue;
                    $pdfDetails = pdf_fetch($cert['pdfUrl']);
                    if (isset($pdfDetails['operator']['lfbisNr'])) $op['lfbisNr'] = $pdfDetails['operator']['lfbisNr'];
                    if (!isset($pdfDetails['id'])) continue;
                    if (preg_match("/\.([0-9]{3}-[0-9]{7})\./", $pdfDetails['id'], $matches) === 1) {
                        $ooId = $matches[1];
                    }
                }
            }
        }
        if ($ooId === null)
            continue;
        update_local($ooId, ['plz' => $postalCode, 'bioc' => "$op[id]"]);
    }
    foreach ($data[2] as $op) {
        // bioqs
        $ooId = find_local("bioqs:$op[id]");
        $lfbisNr = null;
        if ($ooId === null || $lfbisNr === null) {
            foreach ($op['certificates'] as $cert) {
                if (preg_match("/\.([0-9]{3}-[0-9]{7})\./", $cert['nr'], $matches) === 1) {
                    $ooId = $matches[1];
                }
            }
            if ($ooId === null || $lfbisNr === null) {
                foreach ($op['certificates'] as $cert) {
                    if ($cert['pdfUrl'] === null) continue;
                    $pdfDetails = pdf_fetch($cert['pdfUrl']);
                    if (isset($pdfDetails['operator']['lfbisNr'])) $lfbisNr = $pdfDetails['operator']['lfbisNr'];
                    if (!isset($pdfDetails['id'])) continue;
                    if (preg_match("/\.([0-9]{3}-[0-9]{7})\./", $pdfDetails['id'], $matches) === 1) {
                        $ooId = $matches[1];
                    }
                }
            }
        }
        if ($ooId === null)
            continue;
        update_local($ooId, ['plz' => $postalCode, 'lfbis' => $lfbisNr, 'bioqs' => "$op[id]"]);
    }
    foreach ($data[3] as $op) {
        // lkv
        $ooId = find_local("lkv:$op[id]");
        if ($ooId === null)
            continue;
        update_local($ooId, ['plz' => $postalCode, 'lfbis' => $op['lfbisNr'], 'lkv' => "$op[id]"]);
        update_local($ooId, ['plz' => $postalCode, 'lfbis' => $op['lfbisNr'], 'lkv' => "$op[id]"]);
    }
}

$info = substr($_SERVER['PATH_INFO'], 1);
if ($info === '') {
    // search
    $limit = $_GET['limit'] ?? null;
    $offset = intval($_GET['offset'] ?? "0");
    if ($limit === '') $limit = null;
    if ($limit !== null) $limit = intval($limit);

    $country = $_GET['country'] ?? null;
    $postalCode = $_GET['postalCode'] ?? null;
    if ($country === null || $postalCode === null) {
        header('Status: 400');
        header('Content-Length: 109');
        echo "{\"error\":\"bad request\",\"message\":\"The 'country' and 'postalCode' request URL query parameters are required\"}\n";
        exit;
    }

    update_cache($country, $postalCode);

    echo "{\"data\":[";
    if ($country === 'AT') {
        $first = true;
        foreach (scandir('.ids/') as $file) {
            if (!str_ends_with($file, '.txt') || !str_starts_with($file, '040-')) continue;
            $id = substr($file, 0, strlen($file) - 4);
            $data = file_get_contents(".ids/$file");
            if (str_starts_with($data, "plz:$postalCode\n")) {
                preg_match("/^name:(.*?)\|(.*?)\|([0-9]{4}) (.*?)$/m", $data, $name);
                preg_match("/^lfbis:(.*?)$/m", $data, $lfbis);
                if (!$first) echo ",";
                echo "\n  ";
                echo jenc([
                    'id' => $id,
                    'lfbisNr' => $lfbis[1],
                    'name' => $name[1],
                    'address' => $name[2],
                    'postalCode' => $name[3],
                    'city' => $name[4],
                    'country' => $country,
                    'url' => "https://elwig.at/organic/operators/$id",
                ]);
                $first = false;
            }
        }
    }
    echo "\n]}\n";

    exit;
}

if (preg_match("/^((easy-cert:[a-z]+|bioqs|bioc|lkv):[0-9a-zA-Z-_]+|lfbis:[0-9]+)$/", $info) === 1) {
    $found = find_local($info);
    if ($found !== null) {
        header('Status: 303');
        header('Location: /organic/operators/' . $found);
        header('Content-Length: 0');
        exit;
    }
    header('Status: 404');
    header('Content-Length: 22');
    echo "{\"error\":\"not found\"}\n";
    exit;
} else if (!file_exists(".ids/$info.txt")) {
    header('Status: 404');
    header('Content-Length: 22');
    echo "{\"error\":\"not found\"}\n";
    exit;
}

$data = file_get_contents(".ids/$info.txt");
preg_match("/^name:(.*?)\|(.*?)\|([0-9]{4}) (.*?)$/m", $data, $name);
preg_match("/^lfbis:(.*?)$/m", $data, $lfbis);
preg_match("/^easy-cert:(.*?)$/m", $data, $easyCert);
preg_match("/^bioqs:(.*?)$/m", $data, $bioQs);
preg_match("/^bioc:(.*?)$/m", $data, $bioC);

if (sizeof($easyCert) > 1 && ($opDetails = jget("https://elwig.at/organic/external/easy-cert/operators/$easyCert[1]")) !== null) {
    foreach ($opDetails['certificates'] as $cert) {
        if ($cert['pdfUrl'] === null) continue;
        pdf_fetch($cert['pdfUrl']);
    }
}
if (sizeof($bioQs) > 1 && ($opDetails = jget("https://elwig.at/organic/external/bioqs/operators/$bioQs[1]")) !== null) {
    foreach ($opDetails['certificates'] as $cert) {
        if ($cert['pdfUrl'] === null) continue;
        pdf_fetch($cert['pdfUrl']);
    }
}
if (sizeof($bioC) > 1 && ($opDetails = jget("https://elwig.at/organic/external/bioc/operators/$bioC[1]")) !== null) {
    foreach ($opDetails['certificates'] as $cert) {
        if ($cert['pdfUrl'] === null) continue;
         pdf_fetch($cert['pdfUrl']);
    }
}

$certs = [];
$certIds = [];
foreach (scandir('../certificates/') as $file) {
    if (!str_contains($file, ".$info."))
        continue;
    $certId = substr($file, 0, 31);
    if (in_array($certId, $certIds))
        continue;
    $certIds[] = $certId;
    $cert = parse_pdf("../certificates/$certId.pdf");
    $appendix = parse_pdf("../certificates/$certId.appendix.pdf");
    if ($cert === null && $appendix === null)
        continue;

    $parts = explode('.', $file);
    $certs[] = [
        'id' => $certId,
        'nr' => $appendix['nr'] ?? null,
        'validFrom' => $cert['validFrom'] ?? null,
        'validTo' => $cert['validTo'] ?? null,
        'authority' => ['code' => $parts[0]],
        'operator' => ['id' => $parts[1]],
        'url' => "https://elwig.at/organic/certificates/$certId",
        'tracesPdfUrl' => $cert !== null ? "https://elwig.at/organic/certificates/$certId.pdf" : null,
        'appendixPdfUrl' => $appendix !== null ? "https://elwig.at/organic/certificates/$certId.appendix.pdf" : null,
    ];
}

$details = [];
if (preg_match("/^easy-cert:(.*?)$/m", $data, $easyCert) === 1)
    $details[] = "https://elwig.at/organic/external/easy-cert/operators/$easyCert[1]";
if (preg_match("/^bioc:(.*?)$/m", $data, $bioc) === 1)
    $details[] = "https://elwig.at/organic/external/bioc/operators/$bioc[1]";
if (preg_match("/^bioqs:(.*?)$/m", $data, $bioqs) === 1)
    $details[] = "https://elwig.at/organic/external/bioqs/operators/$bioqs[1]";
if (preg_match("/^lkv:(.*?)$/m", $data, $lkv) === 1)
    $details[] = "https://elwig.at/organic/external/lkv/operators/$lkv[1]";
echo jenc([
    'id' => $info,
    'lfbisNr' => $lfbis[1],
    'name' => $name[1],
    'address' => $name[2],
    'postalCode' => $name[3],
    'city' => $name[4],
    'country' => 'AT',
    'url' => "https://elwig.at/organic/operators/$info",
    'tracesUrl' => "https://webgate.ec.europa.eu/tracesnt/directory/publication/organic-operator/index#!?query=$info",
    'originUrls' => $details,
    'certificates' => $certs,
]);
