<?php

if (!function_exists('enrep_fail')) {
    function enrep_fail(int $status = 400, string $message = 'Bad request'): void
    {
        if (!headers_sent()) {
            http_response_code($status);
            header('Content-Type: text/plain; charset=utf-8');
        }
        echo $message;
        exit;
    }
}

if (!function_exists('enrep_tenant_segment')) {
    function enrep_tenant_segment(?string $tenant = null): string
    {
        if ($tenant === null) {
            $tenant = (string)($_REQUEST['tenant'] ?? '');
        }

        if ($tenant === '' && defined('TENANT_URL')) {
            $tenant = (string)TENANT_URL;
        }

        $tenant = trim(str_replace('\\', '/', $tenant));
        $tenant = trim($tenant, '/');

        if ($tenant === '') {
            return '';
        }

        if (strpos($tenant, '..') !== false || !preg_match('/\A[A-Za-z0-9][A-Za-z0-9._-]{0,190}\z/', $tenant)) {
            enrep_fail(400, 'Invalid tenant');
        }

        return $tenant;
    }
}

if (!function_exists('enrep_require_tenant_config')) {
    function enrep_require_tenant_config(int $upLevels = 3, ?string $fromDir = null): void
    {
        if (defined('CONFIG_LOADED')) {
            return;
        }

        $tenant = enrep_tenant_segment();
        $candidates = [];

        if ($tenant !== '') {
            $prefix = str_repeat('../', max(0, $upLevels));
            if ($fromDir !== null && $fromDir !== '') {
                $candidates[] = ['path' => $prefix . $tenant . '/config.php', 'cwd' => $fromDir];
            }
            $candidates[] = ['path' => $prefix . $tenant . '/config.php', 'cwd' => null];
            $candidates[] = ['path' => dirname(__DIR__) . '/' . $tenant . '/config.php', 'cwd' => null];
            $candidates[] = ['path' => dirname(__DIR__) . '/../' . $tenant . '/config.php', 'cwd' => null];
        }

        $candidates[] = ['path' => '/config.php', 'cwd' => null];

        foreach ($candidates as $candidate) {
            $path = $candidate['path'];
            $cwd = $candidate['cwd'];
            $previousCwd = false;

            if ($cwd !== null && is_dir($cwd)) {
                $previousCwd = getcwd();
                chdir($cwd);
            }

            if (is_file($path)) {
                require_once $path;

                if ($previousCwd !== false) {
                    chdir($previousCwd);
                }
                return;
            }

            if ($previousCwd !== false) {
                chdir($previousCwd);
            }
        }

        enrep_fail(400, 'Tenant config not found');
    }
}

if (!function_exists('enrep_request_string')) {
    function enrep_request_string(string $key, string $default = '', int $maxLength = 1000): string
    {
        $value = $_REQUEST[$key] ?? $default;
        if (is_array($value)) {
            return $default;
        }

        $value = trim((string)$value);
        if ($maxLength > 0 && strlen($value) > $maxLength) {
            $value = substr($value, 0, $maxLength);
        }

        return $value;
    }
}

if (!function_exists('enrep_request_int')) {
    function enrep_request_int(string $key, int $default = 0): int
    {
        $value = $_REQUEST[$key] ?? $default;
        if (is_array($value)) {
            return $default;
        }

        return filter_var($value, FILTER_VALIDATE_INT) !== false ? (int)$value : $default;
    }
}

if (!function_exists('enrep_request_enum')) {
    function enrep_request_enum(string $key, array $allowed, string $default = ''): string
    {
        $value = enrep_request_string($key, $default, 120);
        return in_array($value, $allowed, true) ? $value : $default;
    }
}

if (!function_exists('enrep_request_int_array')) {
    function enrep_request_int_array(string $key): array
    {
        $value = $_REQUEST[$key] ?? [];
        if (!is_array($value)) {
            $value = [$value];
        }

        $out = [];
        foreach ($value as $item) {
            if (filter_var($item, FILTER_VALIDATE_INT) !== false) {
                $out[] = (int)$item;
            }
        }

        return array_values(array_unique($out));
    }
}

if (!function_exists('enrep_int_list_from_mixed')) {
    function enrep_int_list_from_mixed($value): array
    {
        if (is_array($value)) {
            $parts = $value;
        } else {
            $parts = preg_split('/[,\s|]+/', (string)$value, -1, PREG_SPLIT_NO_EMPTY);
        }

        $out = [];
        foreach ($parts as $part) {
            $part = trim((string)$part);
            if (preg_match('/\A[Cc]?([0-9]+)\z/', $part, $matches)) {
                $out[] = (int)$matches[1];
            }
        }

        return array_values(array_unique($out));
    }
}

if (!function_exists('enrep_request_int_list')) {
    function enrep_request_int_list(string $key): array
    {
        return enrep_int_list_from_mixed($_REQUEST[$key] ?? '');
    }
}

if (!function_exists('enrep_safe_relative_path')) {
    function enrep_safe_relative_path(string $path, bool $allowEmpty = false): string
    {
        $path = trim(str_replace('\\', '/', $path));

        if ($path === '') {
            if ($allowEmpty) {
                return '';
            }
            enrep_fail(400, 'Invalid path');
        }

        if (
            strpos($path, "\0") !== false ||
            substr($path, 0, 1) === '/' ||
            preg_match('#(^|/)\.\.(/|$)#', $path) ||
            !preg_match('#\A[A-Za-z0-9._/\- ]+\z#', $path)
        ) {
            enrep_fail(400, 'Invalid path');
        }

        return trim($path, '/');
    }
}

if (!function_exists('enrep_safe_filename')) {
    function enrep_safe_filename(string $filename): string
    {
        $filename = basename(str_replace('\\', '/', $filename));
        $filename = preg_replace('/[^A-Za-z0-9._ -]/', '_', $filename);
        $filename = trim((string)$filename, " .\t\n\r\0\x0B");

        if ($filename === '') {
            enrep_fail(400, 'Invalid file');
        }

        return $filename;
    }
}

if (!function_exists('enrep_tenant_path')) {
    function enrep_tenant_path(string $tenant, string ...$parts): string
    {
        $tenant = enrep_tenant_segment($tenant);
        $safeParts = [];

        foreach ($parts as $part) {
            $safe = enrep_safe_relative_path($part, true);
            if ($safe !== '') {
                $safeParts[] = $safe;
            }
        }

        return '../../' . $tenant . (empty($safeParts) ? '' : '/' . implode('/', $safeParts));
    }
}

if (!function_exists('enrep_require_admin')) {
    function enrep_require_admin(): void
    {
        if (session_status() === PHP_SESSION_NONE) {
            session_start();
        }

        if (($_SESSION['usertype'] ?? '') !== 'admins' || (int)($_SESSION['access'] ?? 0) < 1) {
            enrep_fail(403, 'Forbidden');
        }
    }
}

if (!function_exists('enrep_require_user')) {
    function enrep_require_user(): void
    {
        if (session_status() === PHP_SESSION_NONE) {
            session_start();
        }

        if ((string)($_SESSION['usertype'] ?? '') === '' || (int)($_SESSION['access'] ?? 0) < 1) {
            enrep_fail(403, 'Forbidden');
        }
    }
}
