<?php

namespace App\Filament\Resources\ProviderConnectionResource\Pages;

use App\Filament\Resources\ProviderConnectionResource;
use App\Models\ManagedEnvironment;
use App\Models\OperationRun;
use App\Models\ProviderConnection;
use App\Models\User;
use App\Services\Auth\CapabilityResolver;
use App\Services\Intune\AuditLogger;
use App\Support\Auth\Capabilities;
use App\Support\OperationRunLinks;
use App\Support\Providers\TargetScope\ProviderConnectionTargetScopeDescriptor;
use App\Support\Providers\TargetScope\ProviderConnectionTargetScopeNormalizer;
use App\Support\Rbac\UiEnforcement;
use Filament\Actions;
use Filament\Actions\Action;
use Filament\Resources\Pages\EditRecord;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Validation\ValidationException;

class EditProviderConnection extends EditRecord
{
    protected static string $resource = ProviderConnectionResource::class;

    public ?string $scopedTenantExternalId = null;

    protected bool $shouldMakeDefault = false;

    protected bool $defaultWasChanged = false;

    public function mount($record): void
    {
        parent::mount($record);

        $recordTenant = $this->record instanceof ProviderConnection
            ? ProviderConnectionResource::resolveTenantForRecord($this->record)
            : null;

        if ($recordTenant instanceof ManagedEnvironment) {
            $this->scopedTenantExternalId = (string) $recordTenant->slug;

            return;
        }

        $tenantIdFromQuery = request()->query('environment_id');

        if (is_numeric($tenantIdFromQuery)) {
            $environment = ManagedEnvironment::query()->whereKey((int) $tenantIdFromQuery)->first();

            if ($environment instanceof ManagedEnvironment) {
                $this->scopedTenantExternalId = (string) $environment->slug;
            }

            return;
        }

        $tenant = request()->route('tenant');

        if ($tenant instanceof ManagedEnvironment) {
            $this->scopedTenantExternalId = (string) $tenant->slug;

            return;
        }

        if (is_string($tenant) && $tenant !== '') {
            $this->scopedTenantExternalId = $tenant;
        }
    }

    protected function mutateFormDataBeforeSave(array $data): array
    {
        $this->shouldMakeDefault = (bool) ($data['is_default'] ?? false);
        unset($data['is_default']);

        $targetScope = app(ProviderConnectionTargetScopeNormalizer::class)->normalizeInput(
            provider: 'microsoft',
            scopeKind: ProviderConnectionTargetScopeDescriptor::SCOPE_KIND_TENANT,
            scopeIdentifier: (string) ($data['entra_tenant_id'] ?? ''),
            scopeDisplayName: (string) ($data['display_name'] ?? ''),
            providerSpecificIdentity: [
                'microsoft_tenant_id' => (string) ($data['entra_tenant_id'] ?? ''),
            ],
        );

        if ($targetScope['status'] !== ProviderConnectionTargetScopeNormalizer::STATUS_NORMALIZED) {
            throw ValidationException::withMessages([
                'entra_tenant_id' => $targetScope['message'],
            ]);
        }

        return $data;
    }

    protected function afterSave(): void
    {
        $record = $this->getRecord();

        $tenant = $record instanceof ProviderConnection
            ? ($record->tenant ?? $this->currentTenant())
            : $this->currentTenant();

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

        $changedFields = array_values(array_diff(array_keys($record->getChanges()), ['updated_at']));

        if ($this->shouldMakeDefault && ! $record->is_default) {
            $record->makeDefault();
            $this->defaultWasChanged = true;
        }

        $hasDefault = $tenant->providerConnections()
            ->where('provider', $record->provider)
            ->where('is_default', true)
            ->exists();

        if (! $hasDefault) {
            $record->makeDefault();
            $this->defaultWasChanged = true;
        }

        $user = auth()->user();
        $actorId = $user instanceof User ? (int) $user->getKey() : null;
        $actorEmail = $user instanceof User ? $user->email : null;
        $actorName = $user instanceof User ? $user->name : null;

        if ($changedFields !== []) {
            app(AuditLogger::class)->log(
                tenant: $tenant,
                action: 'provider_connection.updated',
                context: [
                    'metadata' => ProviderConnectionResource::targetScopeAuditMetadata($record, [
                        'fields' => app(ProviderConnectionTargetScopeNormalizer::class)->auditFieldNames($changedFields),
                    ]),
                ],
                actorId: $actorId,
                actorEmail: $actorEmail,
                actorName: $actorName,
                resourceType: 'provider_connection',
                resourceId: (string) $record->getKey(),
                status: 'success',
            );
        }

        if ($this->defaultWasChanged) {
            app(AuditLogger::class)->log(
                tenant: $tenant,
                action: 'provider_connection.default_set',
                context: [
                    'metadata' => ProviderConnectionResource::targetScopeAuditMetadata($record),
                ],
                actorId: $actorId,
                actorEmail: $actorEmail,
                actorName: $actorName,
                resourceType: 'provider_connection',
                resourceId: (string) $record->getKey(),
                status: 'success',
            );
        }
    }

    protected function getHeaderActions(): array
    {
        $tenant = $this->currentTenant();

        return [
            Actions\DeleteAction::make()
                ->visible(false),

            Actions\ActionGroup::make([
                UiEnforcement::forAction(
                    Action::make('view_last_check_run')
                        ->label('View last check run')
                        ->icon('heroicon-o-eye')
                        ->color('gray')
                        ->visible(fn (ProviderConnection $record): bool => $tenant instanceof ManagedEnvironment
                            && OperationRun::query()
                                ->where('managed_environment_id', $tenant->getKey())
                                ->where('type', 'provider.connection.check')
                                ->where('context->provider_connection_id', (int) $record->getKey())
                                ->exists())
                        ->url(function (ProviderConnection $record): ?string {
                            $tenant = $this->currentTenant();

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

                            $run = OperationRun::query()
                                ->where('managed_environment_id', $tenant->getKey())
                                ->where('type', 'provider.connection.check')
                                ->where('context->provider_connection_id', (int) $record->getKey())
                                ->orderByDesc('id')
                                ->first();

                            if (! $run instanceof OperationRun) {
                                return null;
                            }

                            return OperationRunLinks::view($run, $tenant);
                        })
                )
                    ->requireCapability(Capabilities::PROVIDER_VIEW)
                    ->tooltip('You do not have permission to view provider connections.')
                    ->preserveVisibility()
                    ->apply(),
                ProviderConnectionResource::makeCheckConnectionAction(),
                ProviderConnectionResource::makeInventorySyncAction(),
                ProviderConnectionResource::makeComplianceSnapshotAction(),
                ProviderConnectionResource::makeSetDefaultAction(),
                ProviderConnectionResource::makeEnableDedicatedOverrideAction(
                    source: 'provider_connection.edit_page',
                    modalDescription: 'Dedicated credentials are stored encrypted and reset consent to the dedicated app registration.',
                ),
                ProviderConnectionResource::makeRotateDedicatedCredentialAction(
                    modalDescription: 'Stores a replacement dedicated client secret and refreshes dedicated identity state.',
                ),
                ProviderConnectionResource::makeDeleteDedicatedCredentialAction(
                    modalDescription: 'Deletes the dedicated credential and leaves the connection blocked until a replacement is added or the type is reverted.',
                ),
                ProviderConnectionResource::makeRevertToPlatformAction(
                    source: 'provider_connection.edit_page',
                    modalDescription: 'Reverts the connection to the platform-managed identity and removes any dedicated credential.',
                ),
                ProviderConnectionResource::makeEnableConnectionAction(),
                ProviderConnectionResource::makeDisableConnectionAction(),
            ])
                ->label('Actions')
                ->icon('heroicon-o-ellipsis-vertical')
                ->color('gray'),
        ];
    }

    protected function getFormActions(): array
    {
        $tenant = $this->currentTenant();

        $user = auth()->user();

        if (! $tenant instanceof ManagedEnvironment || ! $user instanceof User) {
            return [
                $this->getCancelFormAction(),
            ];
        }

        $capabilityResolver = app(CapabilityResolver::class);

        if ($capabilityResolver->can($user, $tenant, Capabilities::PROVIDER_MANAGE)) {
            return parent::getFormActions();
        }

        return [
            $this->getCancelFormAction(),
        ];
    }

    protected function handleRecordUpdate(Model $record, array $data): Model
    {
        $tenant = $record instanceof ProviderConnection
            ? ($record->tenant ?? $this->currentTenant())
            : $this->currentTenant();

        $user = auth()->user();

        if (! $tenant instanceof ManagedEnvironment || ! $user instanceof User) {
            abort(404);
        }

        $capabilityResolver = app(CapabilityResolver::class);

        if (! $capabilityResolver->isMember($user, $tenant)) {
            abort(404);
        }

        if (! $capabilityResolver->can($user, $tenant, Capabilities::PROVIDER_MANAGE)) {
            abort(403);
        }

        return parent::handleRecordUpdate($record, $data);
    }

    private function currentTenant(): ?ManagedEnvironment
    {
        if (isset($this->record) && $this->record instanceof ProviderConnection) {
            $recordTenant = ProviderConnectionResource::resolveTenantForRecord($this->record);

            if ($recordTenant instanceof ManagedEnvironment) {
                return $recordTenant;
            }
        }

        if (is_string($this->scopedTenantExternalId) && $this->scopedTenantExternalId !== '') {
            return ManagedEnvironment::query()
                ->where('slug', $this->scopedTenantExternalId)
                ->first();
        }

        $tenant = request()->route('tenant');

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

        if (is_string($tenant) && $tenant !== '') {
            return ManagedEnvironment::query()
                ->where('slug', $tenant)
                ->first();
        }

        $tenantFromCreateResolution = ProviderConnectionResource::resolveTenantForCreate();

        if ($tenantFromCreateResolution instanceof ManagedEnvironment) {
            return $tenantFromCreateResolution;
        }

        return ManagedEnvironment::current();
    }
}
