<?php

declare(strict_types=1);

namespace App\Filament\Pages;

use App\Exceptions\SupportCenter\SupportCenterException;
use App\Filament\Concerns\InteractsWithDberpPermissions;
use App\Filament\Concerns\RegistersDberpNavigationWhenAccessible;
use App\Filament\Pages\Concerns\InteractsWithDberpNavigationGroupBreadcrumbs;
use App\Services\DberpPermissionService;
use App\Services\SupportCenter\HostSiteOnboardingConfirmService;
use App\Services\SupportCenter\HostSiteOnboardingHeartbeatService;
use App\Services\SupportCenter\HostSiteOnboardingStatusQueryService;
use App\Support\CopyTextToClipboardScript;
use App\Support\SiteOnboardingCenterDisplay;
use BackedEnum;
use Filament\Actions\Action;
use Filament\Forms\Components\TextInput;
use Filament\Infolists\Components\TextEntry;
use Filament\Notifications\Notification;
use Filament\Pages\Page;
use Filament\Schemas\Components\Actions;
use Filament\Schemas\Components\EmbeddedSchema;
use Filament\Schemas\Components\Form;
use Filament\Schemas\Components\Section;
use Filament\Schemas\Schema;
use Filament\Support\Enums\FontFamily;
use Illuminate\Contracts\Support\Htmlable;
use Illuminate\Support\HtmlString;
use Illuminate\Validation\ValidationException;
use Livewire\Attributes\Renderless;
use UnitEnum;

/**
 * @property-read Schema $content
 * @property-read Schema $infolist
 * @property-read Schema $form
 */
final class SiteOnboardingCenterPage extends Page
{
    use InteractsWithDberpNavigationGroupBreadcrumbs;
    use InteractsWithDberpPermissions;
    use RegistersDberpNavigationWhenAccessible;

    protected static ?string $slug = 'site-onboarding-center';

    protected static ?int $navigationSort = 81;

    /**
     * @var array<string, mixed>|null
     */
    public ?array $data = [];

    public bool $showRebindSection = false;

    public static function getNavigationGroup(): string|UnitEnum|null
    {
        return __('dberp.nav.system');
    }

    public static function getNavigationLabel(): string
    {
        return __('dberp.labels.site_onboarding_center');
    }

    public static function getNavigationIcon(): string|BackedEnum|Htmlable|null
    {
        return null;
    }

    public static function canAccess(): bool
    {
        return self::allowsPermission(DberpPermissionService::VIEW_SITE_ONBOARDING);
    }

    public static function canOperateOnboarding(): bool
    {
        return self::allowsPermission(DberpPermissionService::OPERATE_SITE_ONBOARDING);
    }

    public function getTitle(): string|Htmlable
    {
        return __('dberp.site_onboarding.page_title');
    }

    public function getSubheading(): string|Htmlable|null
    {
        $display = app(SiteOnboardingCenterDisplay::class);

        if ($display->isBound()) {
            return __('dberp.site_onboarding.page_intro_after_bound');
        }

        return __('dberp.site_onboarding.page_intro');
    }

    /**
     * @return array<Action>
     */
    protected function getHeaderActions(): array
    {
        return [
            Action::make('copySiteIdentifier')
                ->label(__('dberp.site_onboarding.actions.copy_site_identifier'))
                ->icon('heroicon-o-clipboard-document')
                ->color('gray')
                ->action(fn (): mixed => $this->copySiteIdentifier()),
            Action::make('refreshStatus')
                ->label(__('dberp.site_onboarding.actions.refresh_status'))
                ->icon('heroicon-o-arrow-path')
                ->color('primary')
                ->action(fn (): mixed => $this->refreshStatus())
                ->visible(fn (): bool => self::canOperateOnboarding()),
        ];
    }

    public function mount(): void
    {
        $this->form->fill([
            'access_code' => '',
        ]);

        $display = app(SiteOnboardingCenterDisplay::class);
        $display->ensureInstanceIdentityProvisioned();
        $this->showRebindSection = ! $display->isBound();
    }

    public function content(Schema $schema): Schema
    {
        return $schema->components([
            EmbeddedSchema::make('infolist'),
            Form::make([
                Section::make(fn (): string => $this->accessSectionTitle())
                    ->description(fn (): string|Htmlable|null => $this->accessSectionDescription())
                    ->schema([
                        TextInput::make('access_code')
                            ->label(__('dberp.site_onboarding.fields.access_code'))
                            ->placeholder(__('dberp.site_onboarding.fields.access_code_placeholder'))
                            ->maxLength(191)
                            ->visible(fn (): bool => self::canOperateOnboarding() && $this->showRebindSection),
                    ])
                    ->footer([
                        Actions::make([
                            Action::make('showRebind')
                                ->label(__('dberp.site_onboarding.actions.show_rebind'))
                                ->icon('heroicon-o-key')
                                ->action(fn (): mixed => $this->toggleRebindSection())
                                ->visible(fn (): bool => self::canOperateOnboarding()
                                    && app(SiteOnboardingCenterDisplay::class)->isBound()
                                    && ! $this->showRebindSection),
                            Action::make('confirmAccess')
                                ->label(__('dberp.site_onboarding.actions.confirm_access'))
                                ->icon('heroicon-o-check-badge')
                                ->color('primary')
                                ->action(fn (): mixed => $this->confirmAccess())
                                ->visible(fn (): bool => self::canOperateOnboarding() && $this->showRebindSection),
                            Action::make('reportPresence')
                                ->label(__('dberp.site_onboarding.actions.report_presence'))
                                ->icon('heroicon-o-signal')
                                ->action(fn (): mixed => $this->reportPresence())
                                ->visible(fn (): bool => self::canOperateOnboarding()
                                    && app(SiteOnboardingCenterDisplay::class)->hasSiteNoForHeartbeat()),
                        ]),
                    ]),
            ])
                ->statePath('data')
                ->livewireSubmitHandler(null),
        ]);
    }

    public function defaultForm(Schema $schema): Schema
    {
        return $schema->statePath('data');
    }

    public function form(Schema $schema): Schema
    {
        return $schema->components([]);
    }

    public function defaultInfolist(Schema $schema): Schema
    {
        if (! $schema->hasCustomColumns()) {
            $schema->columns(1);
        }

        return $schema
            ->inlineLabel(false)
            ->record(null);
    }

    public function infolist(Schema $schema): Schema
    {
        $display = app(SiteOnboardingCenterDisplay::class);

        return $schema->components([
            Section::make(__('dberp.site_onboarding.sections.instance_identity'))
                ->schema([
                    TextEntry::make('site_identity')
                        ->label(__('dberp.site_onboarding.rows.site_identity'))
                        ->state($display->siteIdentityLabel())
                        ->badge()
                        ->color('success'),
                    TextEntry::make('official_access')
                        ->label(__('dberp.site_onboarding.rows.official_access'))
                        ->state($display->officialAccessLabel())
                        ->badge()
                        ->color(fn (): string => $display->officialAccessBadgeColor()),
                    TextEntry::make('next_step')
                        ->label(__('dberp.site_onboarding.rows.next_step'))
                        ->state($display->nextStepLabel())
                        ->columnSpanFull(),
                ])
                ->columns(2),
            Section::make(__('dberp.site_onboarding.sections.local_readiness'))
                ->schema([
                    TextEntry::make('local_readiness')
                        ->label(__('dberp.site_onboarding.rows.local_readiness'))
                        ->state($display->localReadinessLabel())
                        ->badge()
                        ->color(fn (): string => $display->localReadinessBadgeColor()),
                    TextEntry::make('local_readiness_guidance')
                        ->label(__('dberp.site_onboarding.rows.local_readiness_guidance'))
                        ->state($display->localReadinessGuidance())
                        ->columnSpanFull()
                        ->visible(fn (): bool => $display->shouldShowLocalReadinessGuidance()),
                    TextEntry::make('package_readiness')
                        ->label(__('dberp.site_onboarding.rows.package_readiness'))
                        ->state($display->packageReadinessMessage())
                        ->columnSpanFull()
                        ->visible(fn (): bool => $display->shouldShowPackageReadiness()),
                    TextEntry::make('product')
                        ->label(__('dberp.site_onboarding.rows.product'))
                        ->state($display->productLabel()),
                    TextEntry::make('host_version')
                        ->label(__('dberp.site_onboarding.rows.host_version'))
                        ->state($display->hostVersion()),
                    TextEntry::make('instance_id')
                        ->label(__('dberp.site_onboarding.rows.instance_id'))
                        ->state($display->instanceId())
                        ->copyable()
                        ->copyMessage(__('dberp.site_onboarding.notifications.copy_site_identifier_success'))
                        ->fontFamily(FontFamily::Mono)
                        ->columnSpanFull(),
                ])
                ->columns(3),
            Section::make(__('dberp.site_onboarding.sections.binding_status'))
                ->schema([
                    TextEntry::make('binding_status')
                        ->label(__('dberp.site_onboarding.rows.binding_status'))
                        ->state($display->bindingStatusLabel())
                        ->badge()
                        ->color(fn (): string => $display->bindingStatusBadgeColor()),
                    TextEntry::make('official_site_no')
                        ->label(__('dberp.site_onboarding.rows.official_site_no'))
                        ->state($display->officialSiteNo())
                        ->copyable()
                        ->fontFamily(FontFamily::Mono)
                        ->visible(fn (): bool => filled($display->officialSiteNo())),
                    TextEntry::make('last_status_fetched_at')
                        ->label(__('dberp.site_onboarding.rows.last_status_fetched_at'))
                        ->state($display->lastStatusFetchedAt())
                        ->visible(fn (): bool => filled($display->lastStatusFetchedAt())),
                    TextEntry::make('last_attempt_summary')
                        ->label(__('dberp.site_onboarding.rows.last_attempt_summary'))
                        ->state($display->lastAttemptSummary())
                        ->visible(fn (): bool => $display->shouldShowLastAttemptSummary())
                        ->columnSpanFull(),
                ])
                ->columns(2),
        ]);
    }

    public function confirmAccess(): void
    {
        if (! self::canOperateOnboarding()) {
            $this->notifyOperationDenied();

            return;
        }

        $accessCode = trim((string) ($this->data['access_code'] ?? ''));

        if ($accessCode === '') {
            throw ValidationException::withMessages([
                'data.access_code' => (string) __('dberp.site_onboarding.errors.access_code_required'),
            ]);
        }

        try {
            app(HostSiteOnboardingConfirmService::class)->confirm($accessCode);

            Notification::make()
                ->success()
                ->title(__('dberp.site_onboarding.notifications.confirm_success_title'))
                ->body(__('dberp.site_onboarding.notifications.confirm_success_body'))
                ->send();

            $this->redirect(self::getUrl(), navigate: true);

            return;
        } catch (SupportCenterException $exception) {
            Notification::make()
                ->danger()
                ->title(__('dberp.site_onboarding.notifications.confirm_failed_title'))
                ->body($exception->userFacingMessage())
                ->send();
        }
    }

    public function refreshStatus(): void
    {
        if (! self::canOperateOnboarding()) {
            $this->notifyOperationDenied();

            return;
        }

        try {
            app(HostSiteOnboardingStatusQueryService::class)->refresh();

            Notification::make()
                ->success()
                ->title(__('dberp.site_onboarding.notifications.refresh_success_title'))
                ->body(__('dberp.site_onboarding.notifications.refresh_success_body'))
                ->send();

            $this->redirect(self::getUrl(), navigate: true);

            return;
        } catch (SupportCenterException $exception) {
            Notification::make()
                ->danger()
                ->title(__('dberp.site_onboarding.notifications.refresh_failed_title'))
                ->body($exception->userFacingMessage())
                ->send();
        }
    }

    public function reportPresence(): void
    {
        if (! self::canOperateOnboarding()) {
            $this->notifyOperationDenied();

            return;
        }

        $sent = app(HostSiteOnboardingHeartbeatService::class)->send();

        if ($sent) {
            Notification::make()
                ->success()
                ->title(__('dberp.site_onboarding.notifications.presence_success_title'))
                ->body(__('dberp.site_onboarding.notifications.presence_success_body'))
                ->send();

            return;
        }

        Notification::make()
            ->warning()
            ->title(__('dberp.site_onboarding.notifications.presence_skipped_title'))
            ->body(__('dberp.site_onboarding.notifications.presence_skipped_body'))
            ->send();
    }

    public function toggleRebindSection(): void
    {
        if (! self::canOperateOnboarding()) {
            $this->notifyOperationDenied();

            return;
        }

        $this->showRebindSection = ! $this->showRebindSection;
    }

    #[Renderless]
    public function copySiteIdentifier(): void
    {
        $instanceId = app(SiteOnboardingCenterDisplay::class)->instanceId();

        $this->js(CopyTextToClipboardScript::forLivewire($instanceId));

        Notification::make()
            ->success()
            ->title((string) __('dberp.site_onboarding.notifications.copy_site_identifier_success'))
            ->send();
    }

    private function notifyOperationDenied(): void
    {
        Notification::make()
            ->danger()
            ->title(__('dberp.site_onboarding.notifications.operation_denied_title'))
            ->body(__('dberp.site_onboarding.notifications.operation_denied_body'))
            ->send();
    }

    private function accessSectionTitle(): string
    {
        $display = app(SiteOnboardingCenterDisplay::class);

        if ($display->isBound()) {
            if ($this->showRebindSection) {
                return (string) __('dberp.site_onboarding.sections.rebind');
            }

            return (string) __('dberp.site_onboarding.sections.maintenance');
        }

        return (string) __('dberp.site_onboarding.sections.access');
    }

    private function accessSectionDescription(): string|Htmlable|null
    {
        $display = app(SiteOnboardingCenterDisplay::class);

        if ($display->isBound() && ! $this->showRebindSection) {
            return null;
        }

        $isBound = $display->isBound();
        $intro = $isBound
            ? (string) __('dberp.site_onboarding.sections.rebind_intro')
            : (string) __('dberp.site_onboarding.sections.access_intro');

        $portalUrl = app(SiteOnboardingCenterDisplay::class)->normalizedSupportCenterBaseUrl();

        return new HtmlString(view('components.dberp.site-onboarding.support-center-portal', [
            'intro' => $intro,
            'portalUrl' => $portalUrl,
            'linkLabel' => (string) __('dberp.site_onboarding.links.open_support_center'),
            'hintPrefix' => (string) __('dberp.site_onboarding.sections.access_code_at_portal_prefix'),
            'hintSuffix' => (string) __('dberp.site_onboarding.sections.access_code_at_portal_suffix'),
            'notConfiguredMessage' => (string) __('dberp.site_onboarding.sections.access_portal_not_configured'),
        ])->render());
    }
}
