<?php
require_once __DIR__ . '/../security.php';

if (!function_exists('delivery_shutdown_logger')) {
    function delivery_shutdown_logger(): void
    {
        $error = error_get_last();
        if (!is_array($error) || !in_array((int)$error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR], true)) {
            return;
        }

        $message = '[' . date('Y-m-d H:i:s') . '] ' . ($error['message'] ?? 'Fatal error')
            . ' in ' . ($error['file'] ?? 'unknown') . ':' . ($error['line'] ?? 0) . PHP_EOL;
        @file_put_contents(__DIR__ . '/error_log', $message, FILE_APPEND);

        if (!headers_sent()) {
            http_response_code(500);
            header('Content-Type: application/json; charset=utf-8');
        }

        echo json_encode(['ok' => false, 'error' => 'Delivery output failed'], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
    }
}
register_shutdown_function('delivery_shutdown_logger');

function delivery_json_input(): array
{
    $raw = file_get_contents('php://input');
    $data = json_decode((string)$raw, true);
    if (!is_array($data)) {
        enrep_fail(400, 'Invalid JSON payload');
    }

    foreach ($data as $key => $value) {
        $_REQUEST[$key] = $value;
    }

    return $data;
}

function delivery_load_tenant(): string
{
    $tenant = enrep_tenant_segment();
    $configLoaded = defined('CONFIG_LOADED');

    if (!$configLoaded) {
        $tenantRoots = [];
        if ($tenant !== '') {
            $tenantRoots[] = realpath(__DIR__ . '/../../../' . $tenant);
        }
        if (!empty($_SERVER['DOCUMENT_ROOT'])) {
            $tenantRoots[] = realpath((string)$_SERVER['DOCUMENT_ROOT']);
        }

        $tenantRoots = array_values(array_unique(array_filter($tenantRoots)));
        foreach ($tenantRoots as $tenantRoot) {
            $configPath = $tenantRoot . DIRECTORY_SEPARATOR . 'config.php';
            if (!is_file($configPath)) {
                continue;
            }

            $cwd = getcwd();
            chdir($tenantRoot);
            global $systemUser, $admin_host, $admin_db_user, $admin_db_password, $admin_db_name;
            global $dbSrc, $dbUsr, $dbpass, $dbTenant, $master, $con, $path, $admin_con;
            require_once $configPath;
            chdir($cwd);
            $configLoaded = true;
            break;
        }
    }

    if (!$configLoaded && is_file('/config.php')) {
        global $systemUser, $admin_host, $admin_db_user, $admin_db_password, $admin_db_name;
        global $dbSrc, $dbUsr, $dbpass, $dbTenant, $master, $con, $path, $admin_con;
        require_once '/config.php';
    }

    if (!isset($GLOBALS['con']) || !($GLOBALS['con'] instanceof mysqli)) {
        enrep_fail(400, 'Tenant config not found');
    }

    enrep_require_user();
    return $tenant;
}

function delivery_response(array $payload): void
{
    if (!headers_sent()) {
        header('Content-Type: application/json; charset=utf-8');
    }
    echo json_encode($payload, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
    exit;
}

function delivery_manifest(array $payload): array
{
    $manifest = $payload['manifest'] ?? $payload;
    if (!is_array($manifest)) {
        enrep_fail(400, 'Missing delivery manifest');
    }

    $manifest['clientnumber'] = (int)($manifest['clientnumber'] ?? 0);
    $manifest['site'] = (int)($manifest['site'] ?? 0);
    $manifest['reports'] = array_values(array_filter(array_map('delivery_report_normalise', $manifest['reports'] ?? [])));
    $manifest['coverReports'] = array_values(array_filter(array_map(
        'delivery_report_normalise',
        $manifest['coverReports'] ?? $manifest['reports']
    )));
    $manifest['options'] = is_array($manifest['options'] ?? null) ? $manifest['options'] : [];
    $manifest['output'] = is_array($manifest['output'] ?? null) ? $manifest['output'] : [];

    if ($manifest['clientnumber'] < 1) {
        enrep_fail(400, 'Invalid client');
    }

    return $manifest;
}

function delivery_report_normalise($report): ?array
{
    if (!is_array($report)) {
        return null;
    }

    $out = [
        'repnumber' => (int)($report['repnumber'] ?? 0),
        'itemnumber' => (int)($report['itemnumber'] ?? 0),
        'form' => (int)($report['form'] ?? 0),
        'surveyor' => (int)($report['surveyor'] ?? 0),
        'status' => preg_replace('/[^A-Z0-9_ -]/', '', strtoupper((string)($report['status'] ?? ''))),
        'chainId' => preg_replace('/[^A-Za-z0-9_-]/', '', (string)($report['chainId'] ?? '')),
        'chainTitle' => trim((string)($report['chainTitle'] ?? '')),
    ];

    return ($out['repnumber'] > 0 && $out['itemnumber'] > 0) ? $out : null;
}

function delivery_report_token(array $report): string
{
    return (int)$report['repnumber'] . '-' . (int)$report['itemnumber'] . '-' . (int)$report['form'] . '-' . (int)$report['surveyor'];
}

function delivery_report_file(array $report): string
{
    return (int)$report['repnumber'] . '_' . (int)$report['itemnumber'] . '.pdf';
}

function delivery_report_source(int $clientnumber): string
{
    return 'output/reports/' . $clientnumber;
}

function delivery_ws_source(int $clientnumber): string
{
    return 'output/wsfiles/' . $clientnumber;
}

function delivery_file_entry(int $clientnumber, string $file, string $type, ?string $source = null, array $meta = []): array
{
    $entry = [
        'source' => $source ?? delivery_report_source($clientnumber),
        'file' => delivery_safe_file($file),
        'type' => $type,
    ];

    if (isset($meta['repnumber']) && !isset($meta['reportnumber'])) {
        $meta['reportnumber'] = $meta['repnumber'];
    }

    foreach (['reportnumber', 'itemnumber', 'form', 'surveyor', 'contents'] as $key) {
        if (array_key_exists($key, $meta)) {
            $entry[$key] = $meta[$key];
        }
    }

    return $entry;
}

function delivery_safe_file(string $file): string
{
    $file = enrep_safe_filename($file);
    if (!preg_match('/\A[A-Za-z0-9._ -]+\z/', $file)) {
        enrep_fail(400, 'Invalid file');
    }

    return $file;
}

function delivery_tenant_dir(string $tenant): string
{
    $tenantDir = defined('TENANT_URL') ? trim((string)TENANT_URL, "/\\") : $tenant;
    return trim($tenantDir, "/\\");
}

function delivery_output_path(string $tenant, int $clientnumber): string
{
    return '../../../' . delivery_tenant_dir($tenant) . '/output/reports/' . $clientnumber . '/';
}

function delivery_ws_path(string $tenant, int $clientnumber): string
{
    return '../../../' . delivery_tenant_dir($tenant) . '/output/wsfiles/' . $clientnumber . '/';
}

function delivery_generator_include(string $file): string
{
    $generatorDir = realpath(__DIR__ . '/../generators');
    if ($generatorDir === false) {
        enrep_fail(500, 'Delivery generator path not found');
    }

    $target = realpath($generatorDir . '/' . $file);
    if ($target === false || strpos($target, $generatorDir . DIRECTORY_SEPARATOR) !== 0 || !is_file($target)) {
        enrep_fail(400, 'Invalid delivery generator');
    }

    $autoload = realpath(__DIR__ . '/../../packages/mpd/vendor/autoload.php');
    if ($autoload === false || !is_file($autoload)) {
        enrep_fail(500, 'PDF generator library not found');
    }
    require_once $autoload;

    $cwd = getcwd();
    $bufferLevel = ob_get_level();
    $out = '';

    chdir($generatorDir);
    try {
        ob_start();
        include $target;
        $out = ob_get_clean();
    } finally {
        while (ob_get_level() > $bufferLevel) {
            ob_end_clean();
        }
        chdir($cwd);
    }

    return trim((string)$out);
}

function delivery_unique_files(array $files): array
{
    $seen = [];
    $out = [];
    foreach ($files as $file) {
        if (!is_array($file) || empty($file['file'])) {
            continue;
        }
        $entry = [
            'source' => trim((string)($file['source'] ?? ''), '/'),
            'file' => delivery_safe_file((string)$file['file']),
            'type' => preg_replace('/[^A-Za-z0-9_-]/', '', (string)($file['type'] ?? '')),
        ];
        if (isset($file['repnumber']) && !isset($file['reportnumber'])) {
            $file['reportnumber'] = $file['repnumber'];
        }

        foreach (['reportnumber', 'itemnumber', 'form', 'surveyor', 'contents'] as $key) {
            if (array_key_exists($key, $file)) {
                $entry[$key] = $file[$key];
            }
        }
        $key = $entry['source'] . '/' . $entry['file'];
        if (!isset($seen[$key])) {
            $seen[$key] = true;
            $out[] = $entry;
        }
    }
    return $out;
}

function delivery_written_scheme_result(array $manifest, string $tenant): array
{
    if (empty($manifest['options']['attachWrittenScheme'])) {
        return ['files' => [], 'warnings' => []];
    }

    $clientnumber = (int)$manifest['clientnumber'];
    $path = delivery_ws_path($tenant, $clientnumber);
    $source = delivery_ws_source($clientnumber);
    $seen = [];
    $files = [];
    $warnings = [];

    foreach ($manifest['reports'] as $report) {
        $itemnumber = (int)$report['itemnumber'];
        $stmt = $GLOBALS['con']->prepare("SELECT `wsnumber` FROM `wsitems` WHERE `itemnumber`=? LIMIT 1");
        if (!$stmt) {
            continue;
        }
        $stmt->bind_param('i', $itemnumber);
        $stmt->execute();
        $res = $stmt->get_result();
        $stmt->close();
        $row = mysqli_fetch_array($res);
        $wsnumber = trim((string)($row['wsnumber'] ?? ''));
        if ($wsnumber === '' || isset($seen[$wsnumber])) {
            continue;
        }
        $seen[$wsnumber] = true;
        $file = 'WS' . preg_replace('/[^A-Za-z0-9_-]/', '', $wsnumber) . '.pdf';
        if (is_file($path . $file)) {
            $files[] = delivery_file_entry($clientnumber, $file, 'ws', $source);
        } else {
            $warnings[] = 'Written Scheme ' . $file . ' is linked to an item, but the file has not been created yet and was not attached.';
        }
    }

    return ['files' => $files, 'warnings' => array_values(array_unique($warnings))];
}

function delivery_written_scheme_files(array $manifest, string $tenant): array
{
    $result = delivery_written_scheme_result($manifest, $tenant);
    return $result['files'];
}
