<?php

namespace App\Modules\Lemmy\Services;

use App\Modules\Lemmy\LemmyRequest;
use Illuminate\Support\Facades\Http;
use Throwable;

class ThumbnailUploader
{
    private const MAX_WIDTH = 600;

    // A 4000x2256 JPEG decodes to ~27MB in GD; the worker runs with memory_limit=128M.
    private const MAX_SOURCE_BYTES = 10_485_760;

    private const MAX_SOURCE_PIXELS = 50_000_000;

    private const JPEG_QUALITY = 82;

    public function __construct(private string $instance) {}

    /**
     * Returns an instance-hosted URL for a downscaled copy, or null if anything fails.
     */
    public function upload(?string $sourceUrl, string $token): ?string
    {
        if ($sourceUrl === null || $sourceUrl === '') {
            return null;
        }

        try {
            $source = $this->download($sourceUrl);

            if ($source === null) {
                return null;
            }

            $resized = $this->resize($source);

            if ($resized === null) {
                return null;
            }

            return $this->store($resized, $token);
        } catch (Throwable) {
            return null;
        }
    }

    private function download(string $url): ?string
    {
        $response = Http::timeout(30)->get($url);

        if (! $response->successful()) {
            return null;
        }

        $body = $response->body();

        return strlen($body) > self::MAX_SOURCE_BYTES ? null : $body;
    }

    private function resize(string $source): ?string
    {
        $info = @getimagesizefromstring($source);

        if ($info === false) {
            return null;
        }

        [$width, $height] = $info;

        if ($width < 1 || $height < 1 || $width * $height > self::MAX_SOURCE_PIXELS) {
            return null;
        }

        if ($width <= self::MAX_WIDTH) {
            return $source;
        }

        $image = @imagecreatefromstring($source);

        if ($image === false) {
            return null;
        }

        $targetHeight = (int) max(1, round($height * (self::MAX_WIDTH / $width)));
        $resized = imagescale($image, self::MAX_WIDTH, $targetHeight);
        imagedestroy($image);

        if ($resized === false) {
            return null;
        }

        ob_start();

        try {
            imagejpeg($resized, null, self::JPEG_QUALITY);
        } finally {
            $bytes = (string) ob_get_clean();
            imagedestroy($resized);
        }

        return $bytes === '' ? null : $bytes;
    }

    private function store(string $bytes, string $token): ?string
    {
        $response = (new LemmyRequest($this->instance, $token))
            ->postMultipart('pictrs/image', 'images[]', $bytes, 'thumbnail.jpg');

        if (! $response->successful()) {
            return null;
        }

        $file = $response->json('files.0.file');

        if (! is_string($file) || $file === '') {
            return null;
        }

        // $instance is a full scheme-qualified URL — platform_accounts.instance_url is validated as a URL.
        return sprintf('%s/pictrs/image/%s', rtrim($this->instance, '/'), $file);
    }
}
