<?php

namespace Inside\DESK\Services;

use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Inside\DESK\Contracts\UrlSigner;

class UrlSignerService implements UrlSigner
{
    private const SIGNATURE_PARAMETER = 'signature';

    public function signedRoute(string $name, array $parameters = [], ?bool $secure = null): string
    {
        $signature = hash_hmac(
            'sha256',
            route($name, $parameters, $secure),
            config('app.key'),
        );

        return route($name, $parameters + [self::SIGNATURE_PARAMETER => $signature], $secure);
    }

    public function hasValidSignature(Request $request, array $ignoreQuery = []): bool
    {
        $ignoreQuery[] = self::SIGNATURE_PARAMETER;

        $originalQuery = collect(explode('&', (string) $request->getQueryString()))
            ->reject(fn ($parameter) => in_array(Str::before($parameter, '='), $ignoreQuery))
            ->implode('&'); // todo use join

        $baseUrl = rtrim(config('app.url').'/'.$request->path(), '/');
        $originalUrl = rtrim($baseUrl.'?'.$originalQuery, '?');

        $expectedSignature = hash_hmac('sha256', $originalUrl, config('app.key'));

        /** @var string $signature */
        $signature = $request->query(self::SIGNATURE_PARAMETER, '');

        return hash_equals($expectedSignature, $signature);
    }
}
