<?php

declare(strict_types=1);

namespace App\Policies;

use App\Models\FindingException;
use App\Models\ManagedEnvironment;
use App\Models\User;
use App\Models\Workspace;
use App\Services\Auth\CapabilityResolver;
use App\Services\Auth\WorkspaceCapabilityResolver;
use App\Support\Auth\Capabilities;
use App\Support\Workspaces\WorkspaceContext;
use Filament\Facades\Filament;
use Illuminate\Auth\Access\HandlesAuthorization;
use Illuminate\Auth\Access\Response;

class FindingExceptionPolicy
{
    use HandlesAuthorization;

    public function viewAny(User $user): bool
    {
        $tenant = $this->resolvedTenant();

        if (! $tenant instanceof ManagedEnvironment) {
            return false;
        }

        if (! $user->canAccessTenant($tenant)) {
            return false;
        }

        return app(CapabilityResolver::class)->can($user, $tenant, Capabilities::FINDING_EXCEPTION_VIEW);
    }

    public function view(User $user, FindingException $exception): Response|bool
    {
        $tenant = $this->authorizedTenantOrNull($user, $exception);

        if (! $tenant instanceof ManagedEnvironment) {
            return Response::denyAsNotFound();
        }

        return app(CapabilityResolver::class)->can($user, $tenant, Capabilities::FINDING_EXCEPTION_VIEW);
    }

    public function approve(User $user, FindingException $exception): Response|bool
    {
        return $this->authorizeCanonicalApproval($user, $exception);
    }

    public function reject(User $user, FindingException $exception): Response|bool
    {
        return $this->authorizeCanonicalApproval($user, $exception);
    }

    private function authorizeCanonicalApproval(User $user, FindingException $exception): Response|bool
    {
        $tenant = $exception->tenant;

        if (! $tenant instanceof ManagedEnvironment || ! $user->canAccessTenant($tenant)) {
            return Response::denyAsNotFound();
        }

        $workspaceId = app(WorkspaceContext::class)->currentWorkspaceId(request());

        if (! is_int($workspaceId) || $workspaceId !== (int) $exception->workspace_id) {
            return Response::denyAsNotFound();
        }

        $workspace = $tenant->workspace;

        if (! $workspace instanceof Workspace) {
            return Response::denyAsNotFound();
        }

        /** @var WorkspaceCapabilityResolver $resolver */
        $resolver = app(WorkspaceCapabilityResolver::class);

        if (! $resolver->isMember($user, $workspace)) {
            return Response::denyAsNotFound();
        }

        return $resolver->can($user, $workspace, Capabilities::FINDING_EXCEPTION_APPROVE)
            ? true
            : Response::deny();
    }

    private function authorizedTenantOrNull(User $user, FindingException $exception): ?ManagedEnvironment
    {
        $tenant = $this->resolvedTenant();

        if (! $tenant instanceof ManagedEnvironment) {
            return null;
        }

        if (! $user->canAccessTenant($tenant)) {
            return null;
        }

        if ((int) $exception->managed_environment_id !== (int) $tenant->getKey()) {
            return null;
        }

        if ((int) $exception->workspace_id !== (int) $tenant->workspace_id) {
            return null;
        }

        return $tenant;
    }

    private function resolvedTenant(): ?ManagedEnvironment
    {
        if (Filament::getCurrentPanel()?->getId() === 'admin') {
            $workspaceId = app(WorkspaceContext::class)->currentWorkspaceId(request());

            if (! is_int($workspaceId)) {
                return null;
            }

            $tenantId = app(WorkspaceContext::class)->lastEnvironmentId(request());

            if (! is_int($tenantId)) {
                return null;
            }

            $tenant = ManagedEnvironment::query()->whereKey($tenantId)->first();

            return $tenant instanceof ManagedEnvironment && (int) $tenant->workspace_id === $workspaceId ? $tenant : null;
        }

        $tenant = ManagedEnvironment::current();

        return $tenant instanceof ManagedEnvironment ? $tenant : null;
    }
}
