<?php

declare(strict_types=1);

namespace App\Filament\Pages;

use App\Filament\Pages\Governance\GovernanceInbox;
use App\Filament\Widgets\Dashboard\DashboardKpis;
use App\Filament\Widgets\Dashboard\EnvironmentDashboardContextChips;
use App\Filament\Widgets\Dashboard\EnvironmentDashboardOverview;
use App\Filament\Widgets\ManagedEnvironment\ManagedEnvironmentTriageArrivalContinuity;
use App\Models\ManagedEnvironment;
use App\Models\SupportRequest;
use App\Models\User;
use App\Services\Audit\WorkspaceAuditLogger;
use App\Services\Auth\CapabilityResolver;
use App\Support\Auth\Capabilities;
use App\Support\EnvironmentDashboard\EnvironmentDashboardSummary;
use App\Support\EnvironmentDashboard\EnvironmentDashboardSummaryBuilder;
use App\Support\ManagedEnvironmentLinks;
use App\Support\ProductTelemetry\ProductTelemetryRecorder;
use App\Support\ProductTelemetry\ProductUsageEventCatalog;
use App\Support\Rbac\UiEnforcement;
use App\Support\SupportDiagnostics\SupportDiagnosticBundleBuilder;
use App\Support\SupportRequests\ExternalSupportDeskHandoffService;
use App\Support\SupportRequests\SupportRequestSubmissionService;
use Filament\Actions\Action;
use Filament\Actions\ActionGroup;
use Filament\Facades\Filament;
use Filament\Forms\Components\Placeholder;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Notifications\Notification;
use Filament\Pages\Dashboard;
use Filament\Schemas\Components\Utilities\Get;
use Filament\Support\Enums\Width;
use Filament\Widgets\Widget;
use Filament\Widgets\WidgetConfiguration;
use Illuminate\Contracts\Support\Htmlable;
use Illuminate\Contracts\View\View;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\HtmlString;

class EnvironmentDashboard extends Dashboard
{
    protected Width|string|null $maxContentWidth = Width::Full;

    /**
     * @var list<string>
     */
    public array $supportDiagnosticsAuditKeys = [];

    private ?EnvironmentDashboardSummary $dashboardSummary = null;

    public static function getNavigationLabel(): string
    {
        return __('localization.dashboard.environment_title');
    }

    public function getTitle(): string|Htmlable
    {
        $tenant = Filament::getTenant();

        if (! $tenant instanceof ManagedEnvironment) {
            return __('localization.dashboard.environment_title');
        }

        $summary = $this->dashboardSummary();

        if (! $summary instanceof EnvironmentDashboardSummary) {
            return (string) $tenant->name;
        }

        return new HtmlString(sprintf(
            '<span class="inline-flex flex-wrap items-center gap-3" data-testid="tenant-dashboard-heading"><span>%s</span><span data-testid="tenant-dashboard-posture-pill" class="%s">%s</span></span>',
            e((string) $tenant->name),
            e($this->posturePillClasses((string) ($summary->posture['tone'] ?? 'gray'))),
            e((string) ($summary->posture['status'] ?? '')),
        ));
    }

    public function getSubheading(): string|Htmlable|null
    {
        return __('localization.dashboard.overview.page_subheading');
    }

    /**
     * @param  array<mixed>  $parameters
     */
    public static function getUrl(array $parameters = [], bool $isAbsolute = true, ?string $panel = null, ?Model $tenant = null, bool $shouldGuessMissingParameters = false): string
    {
        $resolvedTenant = $tenant instanceof ManagedEnvironment
            ? $tenant
            : (($parameters['tenant'] ?? $parameters['environment'] ?? null) instanceof ManagedEnvironment
                ? ($parameters['tenant'] ?? $parameters['environment'])
                : null);

        if (! $resolvedTenant instanceof ManagedEnvironment) {
            return url('/admin');
        }

        $query = array_diff_key($parameters, array_flip(['tenant', 'environment', 'workspace']));

        return ManagedEnvironmentLinks::viewUrl($resolvedTenant, $query);
    }

    /**
     * @return array<class-string<Widget> | WidgetConfiguration>
     */
    protected function getHeaderWidgets(): array
    {
        return [
            EnvironmentDashboardContextChips::class,
        ];
    }

    public function getHeaderWidgetsColumns(): int|array
    {
        return 1;
    }

    /**
     * @return array<class-string<Widget> | WidgetConfiguration>
     */
    public function getWidgets(): array
    {
        return [
            ManagedEnvironmentTriageArrivalContinuity::class,
            DashboardKpis::class,
            EnvironmentDashboardOverview::class,
        ];
    }

    public function getColumns(): int|array
    {
        return ['default' => 1, 'xl' => 12];
    }

    /**
     * @return array<Action>
     */
    protected function getHeaderActions(): array
    {
        $actions = [];

        if ($primaryAction = $this->primaryFollowUpHeaderAction()) {
            $actions[] = $primaryAction;
        }

        $moreActions = array_values(array_filter([
            $this->secondaryHeaderAction(),
            $this->requestSupportAction(),
            $this->openSupportDiagnosticsAction(),
        ]));

        if ($moreActions !== []) {
            $actions[] = ActionGroup::make($moreActions)
                ->label(__('localization.dashboard.more_actions'))
                ->icon('heroicon-o-ellipsis-horizontal')
                ->color('gray');
        }

        return $actions;
    }

    private function primaryFollowUpHeaderAction(): ?Action
    {
        $payload = $this->primaryFollowUpHeaderPayload();

        if (! is_array($payload)) {
            return $this->governanceInboxHeaderAction();
        }

        return $this->summaryHeaderAction(
            name: 'primaryFollowUp',
            payload: $payload,
            color: 'primary',
            icon: 'heroicon-o-bolt',
        );
    }

    private function secondaryHeaderAction(): ?Action
    {
        $payload = $this->secondaryHeaderPayload();

        if (! is_array($payload)) {
            return null;
        }

        return $this->summaryHeaderAction(
            name: 'reviewOutput',
            payload: $payload,
            color: 'gray',
            icon: 'heroicon-o-document-duplicate',
        );
    }

    /**
     * @return array<string, mixed>|null
     */
    private function primaryFollowUpHeaderPayload(): ?array
    {
        $summary = $this->dashboardSummary();

        if (! $summary instanceof EnvironmentDashboardSummary) {
            return null;
        }

        $payload = $summary->recommendedActions[0] ?? null;

        return is_array($payload) && filled($payload['actionLabel'] ?? null)
            ? $payload
            : null;
    }

    /**
     * @return array<string, mixed>|null
     */
    private function secondaryHeaderPayload(): ?array
    {
        $summary = $this->dashboardSummary();

        if (! $summary instanceof EnvironmentDashboardSummary) {
            return null;
        }

        $primaryPayload = $this->primaryFollowUpHeaderPayload();

        foreach ($summary->readinessCards as $payload) {
            if (! is_array($payload) || ! filled($payload['actionLabel'] ?? null)) {
                continue;
            }

            if (! in_array($payload['key'] ?? null, ['customer_safe_output', 'current_review'], true)) {
                continue;
            }

            if (
                is_array($primaryPayload)
                && ($payload['actionLabel'] ?? null) === ($primaryPayload['actionLabel'] ?? null)
                && ($payload['actionUrl'] ?? null) === ($primaryPayload['actionUrl'] ?? null)
            ) {
                continue;
            }

            return $payload;
        }

        return null;
    }

    private function governanceInboxHeaderAction(): ?Action
    {
        $tenant = Filament::getTenant();
        $user = auth()->user();

        if (! $tenant instanceof ManagedEnvironment || ! $user instanceof User || ! $user->canAccessTenant($tenant)) {
            return null;
        }

        return Action::make('primaryFollowUp')
            ->label(__('localization.dashboard.overview.action_open_governance_inbox'))
            ->icon('heroicon-o-inbox-stack')
            ->color('primary')
            ->url(GovernanceInbox::getUrl(panel: 'admin').'?'.http_build_query([
                'environment_id' => (int) $tenant->getKey(),
            ]));
    }

    /**
     * @param  array<string, mixed>  $payload
     */
    private function summaryHeaderAction(string $name, array $payload, string $color, string $icon): ?Action
    {
        $label = $payload['actionLabel'] ?? null;
        $url = $payload['actionUrl'] ?? null;
        $helperText = $payload['helperText'] ?? null;

        if (! is_string($label) || $label === '') {
            return null;
        }

        if ((! is_string($url) || $url === '') && (! is_string($helperText) || $helperText === '')) {
            return null;
        }

        $action = Action::make($name)
            ->label($label)
            ->icon($icon)
            ->color($color);

        if (is_string($url) && $url !== '') {
            $action->url($url);
        } else {
            $action->disabled();
        }

        if (is_string($helperText) && $helperText !== '') {
            $action->tooltip($helperText);
        }

        return $action;
    }

    private function dashboardSummary(): ?EnvironmentDashboardSummary
    {
        if ($this->dashboardSummary instanceof EnvironmentDashboardSummary) {
            return $this->dashboardSummary;
        }

        $tenant = Filament::getTenant();
        $user = auth()->user();

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

        $this->dashboardSummary = app(EnvironmentDashboardSummaryBuilder::class)->build($tenant, $user);

        return $this->dashboardSummary;
    }

    private function posturePillClasses(string $tone): string
    {
        return match ($tone) {
            'success' => 'inline-flex items-center rounded-full border border-success-200 bg-success-50 px-3 py-1 text-sm font-medium text-success-700 shadow-sm dark:border-success-800 dark:bg-success-500/10 dark:text-success-300',
            'danger' => 'inline-flex items-center rounded-full border border-danger-200 bg-danger-50 px-3 py-1 text-sm font-medium text-danger-700 shadow-sm dark:border-danger-800 dark:bg-danger-500/10 dark:text-danger-300',
            'warning' => 'inline-flex items-center rounded-full border border-warning-200 bg-warning-50 px-3 py-1 text-sm font-medium text-warning-700 shadow-sm dark:border-warning-800 dark:bg-warning-500/10 dark:text-warning-300',
            default => 'inline-flex items-center rounded-full border border-gray-200 bg-white px-3 py-1 text-sm font-medium text-gray-700 shadow-sm dark:border-white/10 dark:bg-white/5 dark:text-gray-300',
        };
    }

    public function authorizeTenantSupportRequest(): void
    {
        $this->resolveCurrentTenantForCapability(Capabilities::SUPPORT_REQUESTS_CREATE);
    }

    private function requestSupportAction(): Action
    {
        $action = Action::make('requestSupport')
            ->label(__('localization.dashboard.request_support'))
            ->icon('heroicon-o-paper-airplane')
            ->color('gray')
            ->slideOver()
            ->stickyModalHeader()
            ->modalHeading(__('localization.dashboard.support_request_heading'))
            ->modalDescription(__('localization.dashboard.support_request_description'))
            ->modalSubmitActionLabel(__('localization.dashboard.submit_request'))
            ->form([
                Placeholder::make('included_context')
                    ->label(__('localization.dashboard.included_context'))
                    ->content(fn (): string => $this->tenantSupportRequestAttachmentSummary())
                    ->columnSpanFull(),
                Placeholder::make('latest_external_handoff')
                    ->label(__('localization.dashboard.latest_external_handoff'))
                    ->content(fn (): string => $this->tenantLatestSupportRequestHandoffSummary())
                    ->columnSpanFull(),
                Select::make('external_handoff_mode')
                    ->label(__('localization.dashboard.external_handoff_mode'))
                    ->options(fn (): array => $this->supportHandoffModeOptions())
                    ->default(SupportRequest::EXTERNAL_HANDOFF_MODE_INTERNAL_ONLY)
                    ->helperText(fn (): string => $this->supportDeskTargetAvailable()
                        ? __('localization.dashboard.external_handoff_mode_helper_available')
                        : __('localization.dashboard.external_handoff_mode_helper_unavailable'))
                    ->required()
                    ->live()
                    ->native(false),
                Placeholder::make('handoff_mutation_scope')
                    ->label(__('localization.dashboard.handoff_mutation_scope'))
                    ->content(fn (Get $get): string => $this->externalHandoffMutationScope($get('external_handoff_mode')))
                    ->columnSpanFull(),
                TextInput::make('external_ticket_reference')
                    ->label(__('localization.dashboard.external_ticket_reference'))
                    ->helperText(__('localization.dashboard.external_ticket_reference_helper'))
                    ->required(fn (Get $get): bool => $get('external_handoff_mode') === SupportRequest::EXTERNAL_HANDOFF_MODE_LINK_EXISTING_TICKET)
                    ->visible(fn (Get $get): bool => $this->supportDeskTargetAvailable()
                        && $get('external_handoff_mode') === SupportRequest::EXTERNAL_HANDOFF_MODE_LINK_EXISTING_TICKET),
                TextInput::make('external_ticket_url')
                    ->label(__('localization.dashboard.external_ticket_url'))
                    ->helperText(__('localization.dashboard.external_ticket_url_helper'))
                    ->url()
                    ->visible(fn (Get $get): bool => $this->supportDeskTargetAvailable()
                        && $get('external_handoff_mode') === SupportRequest::EXTERNAL_HANDOFF_MODE_LINK_EXISTING_TICKET)
                    ->columnSpanFull(),
                Select::make('severity')
                    ->label(__('localization.dashboard.severity'))
                    ->options(SupportRequest::severityOptions())
                    ->default(SupportRequest::SEVERITY_NORMAL)
                    ->required()
                    ->native(false),
                TextInput::make('summary')
                    ->label(__('localization.dashboard.summary'))
                    ->required()
                    ->columnSpanFull(),
                Textarea::make('reproduction_notes')
                    ->label(__('localization.dashboard.reproduction_notes'))
                    ->rows(4)
                    ->columnSpanFull(),
                TextInput::make('contact_name')
                    ->label(__('localization.dashboard.contact_name'))
                    ->default(fn (): ?string => $this->resolveDashboardActor()->name),
                TextInput::make('contact_email')
                    ->label(__('localization.dashboard.contact_email'))
                    ->email()
                    ->default(fn (): ?string => $this->resolveDashboardActor()->email),
            ])
            ->action(function (array $data): void {
                $actor = $this->resolveDashboardActor();
                $tenant = $this->resolveCurrentTenantForCapability(Capabilities::SUPPORT_REQUESTS_CREATE);

                $supportRequest = app(SupportRequestSubmissionService::class)->submitForTenant($tenant, $actor, $data);

                Notification::make()
                    ->title(__('localization.dashboard.support_request_submitted'))
                    ->body($this->supportRequestNotificationBody($supportRequest))
                    ->when(
                        $supportRequest->hasExternalHandoffFailure(),
                        fn (Notification $notification): Notification => $notification->warning(),
                        fn (Notification $notification): Notification => $notification->success(),
                    )
                    ->when(
                        $supportRequest->external_ticket_url !== null,
                        fn (Notification $notification): Notification => $notification->actions([
                            Action::make('openExternalTicket')
                                ->label(__('localization.dashboard.open_external_ticket'))
                                ->url((string) $supportRequest->external_ticket_url, shouldOpenInNewTab: true),
                        ]),
                    )
                    ->send();
            });

        return UiEnforcement::forAction($action)
            ->requireCapability(Capabilities::SUPPORT_REQUESTS_CREATE)
            ->apply();
    }

    private function openSupportDiagnosticsAction(): Action
    {
        $action = Action::make('openSupportDiagnostics')
            ->label(__('localization.dashboard.open_support_diagnostics'))
            ->icon('heroicon-o-lifebuoy')
            ->color('gray')
            ->modal()
            ->slideOver()
            ->stickyModalHeader()
            ->modalHeading(__('localization.dashboard.support_diagnostics'))
            ->modalDescription(__('localization.dashboard.support_diagnostics_description'))
            ->modalSubmitAction(false)
            ->modalCancelAction(fn (Action $action): Action => $action->label(__('localization.dashboard.close')))
            ->mountUsing(function (): void {
                $this->auditTenantSupportDiagnosticsOpen();
            })
            ->modalContent(fn (): View => view('filament.modals.support-diagnostic-bundle', [
                'bundle' => $this->tenantSupportDiagnosticBundle(),
            ]));

        return UiEnforcement::forAction($action)
            ->requireCapability(Capabilities::SUPPORT_DIAGNOSTICS_VIEW)
            ->apply();
    }

    /**
     * @return array<string, mixed>
     */
    public function tenantSupportDiagnosticBundle(): array
    {
        $user = $this->resolveDashboardActor();
        $tenant = $this->resolveCurrentTenantForCapability(Capabilities::SUPPORT_DIAGNOSTICS_VIEW);

        return app(SupportDiagnosticBundleBuilder::class)->forTenant($tenant, $user);
    }

    private function auditTenantSupportDiagnosticsOpen(): void
    {
        $user = $this->resolveDashboardActor();
        $tenant = $this->resolveCurrentTenantForCapability(Capabilities::SUPPORT_DIAGNOSTICS_VIEW);

        $this->recordSupportDiagnosticsOpened(
            tenant: $tenant,
            bundle: $this->tenantSupportDiagnosticBundle(),
            user: $user,
        );
    }

    /**
     * @param  array<string, mixed>  $bundle
     */
    private function recordSupportDiagnosticsOpened(ManagedEnvironment $tenant, array $bundle, User $user): void
    {
        $auditKey = 'tenant:'.$tenant->getKey();

        if (in_array($auditKey, $this->supportDiagnosticsAuditKeys, true)) {
            return;
        }

        app(WorkspaceAuditLogger::class)->logSupportDiagnosticsOpened(
            tenant: $tenant,
            contextType: 'tenant',
            bundle: $bundle,
            actor: $user,
        );

        app(ProductTelemetryRecorder::class)->record(
            eventName: ProductUsageEventCatalog::SUPPORT_DIAGNOSTICS_OPENED,
            workspaceId: (int) $tenant->workspace_id,
            tenantId: (int) $tenant->getKey(),
            userId: (int) $user->getKey(),
            subjectType: 'tenant',
            subjectId: (int) $tenant->getKey(),
            metadata: [
                'source_surface' => 'tenant_dashboard',
            ],
        );

        $this->supportDiagnosticsAuditKeys[] = $auditKey;
    }

    private function resolveDashboardActor(): User
    {
        $user = auth()->user();

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

        return $user;
    }

    private function resolveCurrentTenantForCapability(string $capability): ManagedEnvironment
    {
        $user = $this->resolveDashboardActor();
        $tenant = Filament::getTenant();

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

        $resolver = app(CapabilityResolver::class);

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

        if (! $resolver->can($user, $tenant, $capability)) {
            abort(403);
        }

        return $tenant;
    }

    private function tenantSupportRequestAttachmentSummary(): string
    {
        $tenant = Filament::getTenant();
        $user = auth()->user();

        if (! $tenant instanceof ManagedEnvironment || ! $user instanceof User) {
            return 'Only canonical redacted tenant context will be attached.';
        }

        $resolver = app(CapabilityResolver::class);

        if (! $resolver->isMember($user, $tenant)) {
            return 'Only canonical redacted tenant context will be attached.';
        }

        return $resolver->can($user, $tenant, Capabilities::SUPPORT_DIAGNOSTICS_VIEW)
            ? 'A redacted diagnostic snapshot and the canonical tenant context will be attached.'
            : 'Only the canonical redacted tenant context will be attached because you cannot view support diagnostics.';
    }

    private function tenantLatestSupportRequestHandoffSummary(): string
    {
        $tenant = $this->resolveCurrentTenantForCapability(Capabilities::SUPPORT_REQUESTS_CREATE);
        $user = $this->resolveDashboardActor();

        $summary = app(SupportRequestSubmissionService::class)->latestTenantHandoffSummary($tenant, $user);

        return $this->formatLatestHandoffSummary($summary);
    }

    /**
     * @return array<string, string>
     */
    private function supportHandoffModeOptions(): array
    {
        if (! $this->supportDeskTargetAvailable()) {
            return [
                SupportRequest::EXTERNAL_HANDOFF_MODE_INTERNAL_ONLY => __('localization.dashboard.handoff_mode_internal_only'),
            ];
        }

        return [
            SupportRequest::EXTERNAL_HANDOFF_MODE_INTERNAL_ONLY => __('localization.dashboard.handoff_mode_internal_only'),
            SupportRequest::EXTERNAL_HANDOFF_MODE_CREATE_EXTERNAL_TICKET => __('localization.dashboard.handoff_mode_create_external_ticket'),
            SupportRequest::EXTERNAL_HANDOFF_MODE_LINK_EXISTING_TICKET => __('localization.dashboard.handoff_mode_link_existing_ticket'),
        ];
    }

    private function supportDeskTargetAvailable(): bool
    {
        return app(ExternalSupportDeskHandoffService::class)->targetIsConfigured();
    }

    private function externalHandoffMutationScope(mixed $mode): string
    {
        return match ($mode) {
            SupportRequest::EXTERNAL_HANDOFF_MODE_CREATE_EXTERNAL_TICKET => __('localization.dashboard.mutation_scope_external_create'),
            SupportRequest::EXTERNAL_HANDOFF_MODE_LINK_EXISTING_TICKET => __('localization.dashboard.mutation_scope_external_link'),
            default => __('localization.dashboard.mutation_scope_internal_only'),
        };
    }

    /**
     * @param  array<string, mixed>|null  $summary
     */
    private function formatLatestHandoffSummary(?array $summary): string
    {
        if ($summary === null) {
            return __('localization.dashboard.latest_external_handoff_none');
        }

        $internalReference = (string) $summary['internal_reference'];

        if (($summary['has_failure'] ?? false) === true) {
            return __('localization.dashboard.latest_external_handoff_failed', [
                'reference' => $internalReference,
                'failure' => (string) $summary['external_handoff_failure_summary'],
            ]);
        }

        if (($summary['has_external_link'] ?? false) === true) {
            return __('localization.dashboard.latest_external_handoff_linked', [
                'reference' => $internalReference,
                'external' => (string) $summary['external_ticket_reference'],
            ]);
        }

        return __('localization.dashboard.latest_external_handoff_internal_only', [
            'reference' => $internalReference,
        ]);
    }

    private function supportRequestNotificationBody(SupportRequest $supportRequest): string
    {
        return match ($supportRequest->externalHandoffOutcome()) {
            SupportRequest::HANDOFF_OUTCOME_EXTERNAL_TICKET_CREATED => __('localization.dashboard.support_request_submitted_created', [
                'reference' => $supportRequest->internal_reference,
                'external' => $supportRequest->external_ticket_reference,
            ]),
            SupportRequest::HANDOFF_OUTCOME_EXTERNAL_TICKET_LINKED => __('localization.dashboard.support_request_submitted_linked', [
                'reference' => $supportRequest->internal_reference,
                'external' => $supportRequest->external_ticket_reference,
            ]),
            SupportRequest::HANDOFF_OUTCOME_EXTERNAL_HANDOFF_FAILED => __('localization.dashboard.support_request_submitted_failed', [
                'reference' => $supportRequest->internal_reference,
                'failure' => $supportRequest->external_handoff_failure_summary,
            ]),
            default => __('localization.dashboard.support_request_submitted_internal_only', [
                'reference' => $supportRequest->internal_reference,
            ]),
        };
    }
}
