<?php

namespace App\Http\Middleware;

use App\Master\Models\ApiToken;
use Carbon\Carbon;
use Closure;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Http\Request;
use Mtc\MercuryDataModels\Jobs\TrackApiRequest;
use Symfony\Component\HttpFoundation\Response;

class ApiAuthenticatedRequest
{
    use DispatchesJobs;

    private ApiToken $apiToken;

    /**
     * Handle an incoming request.
     *
     * @param  \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response)  $next
     */
    public function handle(Request $request, Closure $next): Response
    {
        if ($this->failsAuthToken($request)) {
            return \response('Access Denied', 401);
        }

        $start = microtime(true);
        $response =  $next($request);
        $request_length = microtime(true) - $start;

        $this->dispatch(new TrackApiRequest(
            tenant('id'),
            $request->getRequestUri(),
            $request->input(),
            $request->method(),
            $response->getStatusCode(),
            $request_length,
            $this->apiToken,
        ));
        return $response;
    }

    private function failsAuthToken(Request $request): bool
    {
        if (!$request->hasHeader('Authorization')) {
            return true;
        }

        $token = str_replace('Bearer ', '', $request->header('Authorization'));
        $apiToken = ApiToken::query()
            ->whereHas('apiUser', fn($query) => $query->where('is_active', 1))
            ->where('token', $token)
            ->where('expires_at', '>=', Carbon::now())
            ->first();
        if (!$apiToken) {
            return true;
        }

        $has_access_to_tenant = $apiToken->apiUser->tenants()->where('tenant_id', tenant('id'))->exists();
        if (!$has_access_to_tenant) {
            return true;
        }

        $this->apiToken = $apiToken;
        return false;
    }
}
