<?php

if (!function_exists('plupload_send_error')) {
    function plupload_send_error($httpCode, $code, $message)
    {
        http_response_code((int)$httpCode);
        echo json_encode([
            'jsonrpc' => '2.0',
            'error' => [
                'code' => (int)$code,
                'message' => (string)$message,
            ],
            'id' => 'id',
        ]);
        exit;
    }
}

if (!function_exists('plupload_bootstrap')) {
    function plupload_bootstrap()
    {
        date_default_timezone_set('Europe/Warsaw');

        if (session_status() !== PHP_SESSION_ACTIVE) {
            session_start();
        }

        header('Content-Type: application/json; charset=utf-8');
        header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
        header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
        header('Cache-Control: no-store, no-cache, must-revalidate');
        header('Cache-Control: post-check=0, pre-check=0', false);
        header('Pragma: no-cache');
    }
}

if (!function_exists('plupload_require_post')) {
    function plupload_require_post()
    {
        if (($_SERVER['REQUEST_METHOD'] ?? '') !== 'POST') {
            plupload_send_error(405, 405, 'Method not allowed.');
        }
    }
}

if (!function_exists('plupload_require_admin_user')) {
    function plupload_require_admin_user()
    {
        $adminSession = isset($_SESSION['admin']) && $_SESSION['admin'] === true;
        $userId = (int)($_SESSION['user']['id'] ?? 0);

        if (!$adminSession || $userId <= 0) {
            plupload_send_error(403, 403, 'Brak autoryzacji.');
        }

        $sessionOk = isset($_SESSION['check'], $_SESSION['ip'])
            && $_SESSION['check'] === true
            && $_SESSION['ip'] === ($_SERVER['REMOTE_ADDR'] ?? '');

        if (!$sessionOk) {
            plupload_send_error(403, 403, 'Nieprawidlowa sesja.');
        }

        return $userId;
    }
}

if (!function_exists('plupload_validate_token')) {
    function plupload_validate_token($userId)
    {
        $uploadToken = (string)($_REQUEST['upload_token'] ?? '');
        if ($uploadToken === '' || !isset($_SESSION['upload_tokens'][$uploadToken])) {
            plupload_send_error(403, 403, 'Brak tokenu uploadu.');
        }

        $tokenData = $_SESSION['upload_tokens'][$uploadToken];
        $tokenUserId = (int)($tokenData['user_id'] ?? 0);
        $tokenExpires = (int)($tokenData['expires'] ?? 0);

        if ($tokenUserId <= 0 || $tokenUserId !== (int)$userId) {
            plupload_send_error(403, 403, 'Token nie nalezy do aktualnego uzytkownika.');
        }

        if ($tokenExpires < time()) {
            unset($_SESSION['upload_tokens'][$uploadToken]);
            plupload_send_error(403, 403, 'Token wygasl.');
        }

        return [$uploadToken, $tokenData];
    }
}

if (!function_exists('plupload_normalize_filename')) {
    function plupload_normalize_filename($fileName)
    {
        $fileName = basename((string)$fileName);
        $fileName = preg_replace('/[^\w\.-]+/', '-', $fileName);
        $fileName = trim((string)$fileName, '.-');

        if ($fileName === '') {
            $fileName = 'file-' . bin2hex(random_bytes(8));
        }

        return strtolower($fileName);
    }
}

if (!function_exists('plupload_ensure_target_dir')) {
    function plupload_ensure_target_dir($targetDir)
    {
        if (!is_dir($targetDir) && !mkdir($targetDir, 0755, true)) {
            plupload_send_error(500, 100, 'Failed to open temp directory.');
        }
    }
}

if (!function_exists('plupload_build_target_paths')) {
    function plupload_build_target_paths($targetDir, $requestName, $allowedExtensions = null, $blockedExtensions = null, $maxNameLength = 180)
    {
        $fileName = plupload_normalize_filename((string)$requestName);
        $extension = strtolower((string)pathinfo($fileName, PATHINFO_EXTENSION));

        if (is_array($allowedExtensions)) {
            if ($extension === '' || !in_array($extension, $allowedExtensions, true)) {
                plupload_send_error(400, 601, 'Nieobslugiwane rozszerzenie pliku.');
            }
        }

        if (is_array($blockedExtensions)) {
            if ($extension !== '' && in_array($extension, $blockedExtensions, true)) {
                plupload_send_error(400, 601, 'Rozszerzenie pliku jest zablokowane.');
            }
        }

        if (strlen($fileName) > (int)$maxNameLength) {
            $base = substr((string)pathinfo($fileName, PATHINFO_FILENAME), 0, 140);
            $suffix = '-' . bin2hex(random_bytes(4));
            $fileName = $base . $suffix . ($extension !== '' ? '.' . $extension : '');
        }

        if (file_exists($targetDir . DIRECTORY_SEPARATOR . $fileName)) {
            $nameWithoutExt = (string)pathinfo($fileName, PATHINFO_FILENAME);
            $extWithDot = $extension !== '' ? '.' . $extension : '';
            $count = 1;

            while (file_exists($targetDir . DIRECTORY_SEPARATOR . $nameWithoutExt . '_' . $count . $extWithDot)) {
                $count++;
            }

            $fileName = $nameWithoutExt . '_' . $count . $extWithDot;
        }

        $filePath = $targetDir . DIRECTORY_SEPARATOR . $fileName;
        $partPath = $filePath . '.part';

        return [$fileName, $extension, $filePath, $partPath];
    }
}

if (!function_exists('plupload_get_chunks')) {
    function plupload_get_chunks()
    {
        $chunk = max(0, (int)($_REQUEST['chunk'] ?? 0));
        $chunks = max(0, (int)($_REQUEST['chunks'] ?? 0));
        return [$chunk, $chunks];
    }
}

if (!function_exists('plupload_cleanup_stale_parts')) {
    function plupload_cleanup_stale_parts($targetDir, $currentPartPath, $maxFileAge = 18000)
    {
        $dir = @opendir($targetDir);
        if (!$dir) {
            return;
        }

        while (($file = readdir($dir)) !== false) {
            $tmpFilePath = $targetDir . DIRECTORY_SEPARATOR . $file;
            if (!preg_match('/\.part$/', $file)) {
                continue;
            }

            if ($tmpFilePath === $currentPartPath) {
                continue;
            }

            if (@filemtime($tmpFilePath) < (time() - (int)$maxFileAge)) {
                @unlink($tmpFilePath);
            }
        }

        closedir($dir);
    }
}

if (!function_exists('plupload_write_chunk_to_part')) {
    function plupload_write_chunk_to_part($partPath, $chunk)
    {
        $contentType = (string)($_SERVER['HTTP_CONTENT_TYPE'] ?? $_SERVER['CONTENT_TYPE'] ?? '');
        $isMultipart = strpos($contentType, 'multipart') !== false;

        if ($isMultipart) {
            $fileInfo = $_FILES['file'] ?? null;
            if (!is_array($fileInfo) || !isset($fileInfo['tmp_name']) || !is_uploaded_file($fileInfo['tmp_name'])) {
                plupload_send_error(400, 103, 'Failed to move uploaded file.');
            }

            if ((int)($fileInfo['error'] ?? UPLOAD_ERR_OK) !== UPLOAD_ERR_OK) {
                plupload_send_error(400, 104, 'Upload error.');
            }

            $in = fopen($fileInfo['tmp_name'], 'rb');
            $out = fopen($partPath, ((int)$chunk === 0) ? 'wb' : 'ab');

            if (!$in) {
                plupload_send_error(500, 101, 'Failed to open input stream.');
            }

            if (!$out) {
                fclose($in);
                plupload_send_error(500, 102, 'Failed to open output stream.');
            }

            while ($buff = fread($in, 4096)) {
                fwrite($out, $buff);
            }

            fclose($in);
            fclose($out);
            @unlink($fileInfo['tmp_name']);
            return;
        }

        $in = fopen('php://input', 'rb');
        $out = fopen($partPath, ((int)$chunk === 0) ? 'wb' : 'ab');

        if (!$in) {
            plupload_send_error(500, 101, 'Failed to open input stream.');
        }

        if (!$out) {
            fclose($in);
            plupload_send_error(500, 102, 'Failed to open output stream.');
        }

        while ($buff = fread($in, 4096)) {
            fwrite($out, $buff);
        }

        fclose($in);
        fclose($out);
    }
}

if (!function_exists('plupload_assert_size_limit')) {
    function plupload_assert_size_limit($partPath, $maxBytes, $message)
    {
        if (@filesize($partPath) > (int)$maxBytes) {
            @unlink($partPath);
            plupload_send_error(413, 413, (string)$message);
        }
    }
}

if (!function_exists('plupload_is_last_chunk')) {
    function plupload_is_last_chunk($chunk, $chunks)
    {
        return ((int)$chunks === 0) || ((int)$chunk === ((int)$chunks - 1));
    }
}

if (!function_exists('plupload_finalize_part')) {
    function plupload_finalize_part($partPath, $filePath)
    {
        if (!@rename($partPath, $filePath)) {
            @unlink($partPath);
            plupload_send_error(500, 105, 'Failed to finalize uploaded file.');
        }
    }
}

if (!function_exists('plupload_create_medoo')) {
    function plupload_create_medoo($database)
    {
        return new medoo([
            'database_type' => 'mysql',
            'database_name' => $database['name'],
            'server' => $database['host'],
            'username' => $database['user'],
            'password' => $database['password'],
            'charset' => 'utf8',
        ]);
    }
}

if (!function_exists('plupload_send_success')) {
    function plupload_send_success(array $payload)
    {
        echo json_encode(array_merge([
            'jsonrpc' => '2.0',
            'result' => null,
            'id' => 'id',
        ], $payload));
        exit;
    }
}

