<?php

namespace App\Providers;

use App\Models\AlertDelivery;
use App\Models\AlertDestination;
use App\Models\AlertRule;
use App\Models\PlatformUser;
use App\Models\ProviderConnection;
use App\Models\ManagedEnvironment;
use App\Models\ManagedEnvironmentOnboardingSession;
use App\Models\EnvironmentReview;
use App\Models\User;
use App\Models\Workspace;
use App\Models\WorkspaceSetting;
use App\Policies\AlertDeliveryPolicy;
use App\Policies\AlertDestinationPolicy;
use App\Policies\AlertRulePolicy;
use App\Policies\ProviderConnectionPolicy;
use App\Policies\ManagedEnvironmentOnboardingSessionPolicy;
use App\Policies\EnvironmentReviewPolicy;
use App\Policies\WorkspaceSettingPolicy;
use App\Services\Auth\CapabilityResolver;
use App\Services\Auth\WorkspaceCapabilityResolver;
use App\Support\Auth\Capabilities;
use App\Support\Auth\PlatformCapabilities;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Gate;

class AuthServiceProvider extends ServiceProvider
{
    protected $policies = [
        ProviderConnection::class => ProviderConnectionPolicy::class,
        ManagedEnvironmentOnboardingSession::class => ManagedEnvironmentOnboardingSessionPolicy::class,
        EnvironmentReview::class => EnvironmentReviewPolicy::class,
        WorkspaceSetting::class => WorkspaceSettingPolicy::class,
        AlertDestination::class => AlertDestinationPolicy::class,
        AlertDelivery::class => AlertDeliveryPolicy::class,
        AlertRule::class => AlertRulePolicy::class,
    ];

    public function boot(): void
    {
        $this->registerPolicies();

        $tenantResolver = app(CapabilityResolver::class);
        $workspaceResolver = app(WorkspaceCapabilityResolver::class);

        $defineTenantCapability = function (string $capability) use ($tenantResolver): void {
            Gate::define($capability, function (User $user, ?ManagedEnvironment $tenant = null) use ($tenantResolver, $capability): bool {
                if (! $tenant instanceof ManagedEnvironment) {
                    return false;
                }

                return $tenantResolver->can($user, $tenant, $capability);
            });
        };

        $defineWorkspaceCapability = function (string $capability) use ($workspaceResolver): void {
            Gate::define($capability, function (User $user, ?Workspace $workspace = null) use ($workspaceResolver, $capability): bool {
                if (! $workspace instanceof Workspace) {
                    return false;
                }

                return $workspaceResolver->can($user, $workspace, $capability);
            });
        };

        foreach (Capabilities::all() as $capability) {
            if (str_starts_with($capability, 'workspace')) {
                $defineWorkspaceCapability($capability);

                continue;
            }

            $defineTenantCapability($capability);
        }

        foreach (PlatformCapabilities::all() as $capability) {
            Gate::define($capability, function (PlatformUser $user) use ($capability): bool {
                return $user->hasCapability($capability);
            });
        }
    }
}
