<?php

namespace App\Modules\Lemmy;

use Illuminate\Http\Client\Response;
use Illuminate\Support\Facades\Http;

class LemmyRequest
{
    // Uploads carry an image payload; the 30s used for JSON calls is not enough.
    private const UPLOAD_TIMEOUT_SECONDS = 60;

    private string $instance;

    private ?string $token;

    private string $scheme = 'https';

    public function __construct(string $instance, ?string $token = null)
    {
        // Detect scheme if provided in the instance string
        if (preg_match('/^(https?):\/\//i', $instance, $m)) {
            $this->scheme = strtolower($m[1]);
        }
        // Handle both full URLs and just domain names
        $this->instance = $this->normalizeInstance($instance);
        $this->token = $token;
    }

    /**
     * Normalize instance URL to just the domain name
     */
    private function normalizeInstance(string $instance): string
    {
        // Remove protocol if present
        $instance = preg_replace('/^https?:\/\//i', '', $instance);

        // Remove trailing slash if present
        $instance = rtrim($instance, '/');

        return $instance;
    }

    /**
     * Explicitly set the scheme (http or https) for subsequent requests.
     */
    public function withScheme(string $scheme): self
    {
        $scheme = strtolower($scheme);
        if (in_array($scheme, ['http', 'https'], true)) {
            $this->scheme = $scheme;
        }

        return $this;
    }

    /**
     * @param  array<string, mixed>  $params
     */
    public function get(string $endpoint, array $params = []): Response
    {
        $url = sprintf('%s://%s/api/v3/%s', $this->scheme, $this->instance, $endpoint);

        $request = Http::timeout(30);

        if ($this->token) {
            $request = $request->withToken($this->token);
        }

        return $request->get($url, $params);
    }

    /**
     * @param  array<string, mixed>  $data
     */
    public function post(string $endpoint, array $data = []): Response
    {
        $url = sprintf('%s://%s/api/v3/%s', $this->scheme, $this->instance, $endpoint);

        $request = Http::timeout(30);

        if ($this->token) {
            $request = $request->withToken($this->token);
        }

        return $request->post($url, $data);
    }

    /**
     * pict-rs is mounted outside the /api/v3 prefix, so this takes a root-relative path.
     *
     * @param  string  $path  Root-relative, e.g. 'pictrs/image'
     * @param  string  $name  Multipart field name, e.g. 'images[]'
     * @param  string  $contents  Raw file bytes
     * @param  string  $filename  Filename sent with the part
     */
    public function postMultipart(string $path, string $name, string $contents, string $filename): Response
    {
        $url = sprintf('%s://%s/%s', $this->scheme, $this->instance, ltrim($path, '/'));

        $request = Http::timeout(self::UPLOAD_TIMEOUT_SECONDS);

        if ($this->token) {
            $request = $request->withToken($this->token);
        }

        return $request->attach($name, $contents, $filename)->post($url);
    }

    public function withToken(string $token): self
    {
        $this->token = $token;

        return $this;
    }
}
