<?php

declare(strict_types=1);

namespace App\Filament\Resources\DberpIntegrationSyncLogs;

use App\Business\Integration\DbshopIntegrationService;
use App\Business\Integration\Enums\IntegrationObjectType;
use App\Business\Integration\Enums\IntegrationSyncStatus;
use App\Business\Report\QueryCenterService;
use App\Filament\Concerns\HidesDberpIntegrationCenterNavigation;
use App\Filament\Concerns\InteractsWithDberpPermissions;
use App\Filament\Resources\Concerns\HasDberpExportAction;
use App\Filament\Resources\DberpIntegrationSyncLogs\Pages\ListDberpIntegrationSyncLogs;
use App\Models\DberpIntegrationSyncLog;
use App\Services\DberpPermissionService;
use App\Support\DberpAuditDisplay;
use BackedEnum;
use Filament\Actions\Action;
use Filament\Actions\BulkAction;
use Filament\Actions\BulkActionGroup;
use Filament\Forms\Components\DatePicker;
use Filament\Forms\Components\TextInput;
use Filament\Notifications\Notification;
use Filament\Resources\Resource;
use Filament\Schemas\Schema;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Filters\Filter;
use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Table;
use Illuminate\Contracts\Support\Htmlable;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection as EloquentCollection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Auth;
use UnitEnum;

class DberpIntegrationSyncLogResource extends Resource
{
    use HasDberpExportAction;
    use HidesDberpIntegrationCenterNavigation;
    use InteractsWithDberpPermissions;

    protected static ?string $model = DberpIntegrationSyncLog::class;

    protected static ?string $recordTitleAttribute = 'reference';

    protected static ?int $navigationSort = 50;

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

    public static function getEloquentQuery(): Builder
    {
        return app(QueryCenterService::class)->integrationSyncLogQuery();
    }

    public static function table(Table $table): Table
    {
        return $table
            ->defaultSort('created_at', 'desc')
            ->columns([
                TextColumn::make('channel')->label(__('dberp.fields.channel'))->searchable(),
                TextColumn::make('source_system')
                    ->label(__('dberp.fields.source_system'))
                    ->badge()
                    ->formatStateUsing(fn (?string $state): string => self::integrationSystemLabel($state)),
                TextColumn::make('target_system')
                    ->label(__('dberp.fields.target_system'))
                    ->badge()
                    ->formatStateUsing(fn (?string $state): string => self::integrationSystemLabel($state)),
                TextColumn::make('sync_object_type')
                    ->label(__('dberp.fields.sync_object_type'))
                    ->badge()
                    ->formatStateUsing(fn (?string $state): string => IntegrationObjectType::tryFrom((string) $state)?->label() ?? (string) $state),
                TextColumn::make('direction')->label(__('dberp.fields.direction'))->badge(),
                TextColumn::make('status')
                    ->label(__('dberp.fields.status'))
                    ->badge()
                    ->formatStateUsing(fn (?string $state): string => IntegrationSyncStatus::tryFrom((string) $state)?->label() ?? (string) $state),
                TextColumn::make('source_document_no')->label(__('dberp.fields.source_document_no'))->searchable(),
                TextColumn::make('external_reference')->label(__('dberp.fields.external_reference'))->searchable(),
                TextColumn::make('reference')->label(__('dberp.fields.reference'))->toggleable(isToggledHiddenByDefault: true),
                TextColumn::make('related_model_label')
                    ->label(__('dberp.fields.related_model'))
                    ->state(fn (DberpIntegrationSyncLog $record): string => self::formatRelatedModel($record)),
                TextColumn::make('error_type')->label(__('dberp.fields.error_type'))->badge(),
                TextColumn::make('result_summary')->label(__('dberp.fields.result_summary'))->limit(50),
                TextColumn::make('retry_count')->label(__('dberp.fields.retry_count')),
                TextColumn::make('latest_retry_status')
                    ->label(__('dberp.fields.latest_retry_status'))
                    ->badge()
                    ->formatStateUsing(fn (?string $state): string => $state === null || $state === '' ? '-' : (IntegrationSyncStatus::tryFrom($state)?->label() ?? $state)),
                TextColumn::make('latest_retry_message')->label(__('dberp.fields.latest_retry_message'))->limit(40),
                TextColumn::make('created_at')->label(__('dberp.fields.created_at'))->dateTime(),
            ])
            ->filters([
                SelectFilter::make('source_system')
                    ->label(__('dberp.fields.source_system'))
                    ->options(__('dberp.integration_ui.source_system_options')),
                SelectFilter::make('target_system')
                    ->label(__('dberp.fields.target_system'))
                    ->options(__('dberp.integration_ui.source_system_options')),
                SelectFilter::make('sync_object_type')->label(__('dberp.fields.sync_object_type'))->options(IntegrationObjectType::options()),
                SelectFilter::make('direction')->label(__('dberp.fields.direction'))->options([
                    'import' => '导入',
                    'export' => '导出',
                ]),
                SelectFilter::make('status')->label(__('dberp.fields.status'))->options(IntegrationSyncStatus::options()),
                Filter::make('source_document_no')
                    ->schema([
                        TextInput::make('value')->label(__('dberp.fields.source_document_no')),
                    ])
                    ->query(fn (Builder $query, array $data): Builder => $query->when($data['value'] ?? null, fn (Builder $builder, $value): Builder => $builder->where('source_document_no', 'like', '%'.$value.'%'))),
                Filter::make('external_reference')
                    ->schema([
                        TextInput::make('value')->label(__('dberp.fields.external_reference')),
                    ])
                    ->query(fn (Builder $query, array $data): Builder => $query->when($data['value'] ?? null, fn (Builder $builder, $value): Builder => $builder->where('external_reference', 'like', '%'.$value.'%'))),
                Filter::make('error_type')
                    ->schema([
                        TextInput::make('value')->label(__('dberp.fields.error_type')),
                    ])
                    ->query(fn (Builder $query, array $data): Builder => $query->when($data['value'] ?? null, fn (Builder $builder, $value): Builder => $builder->where('error_type', 'like', '%'.$value.'%'))),
                Filter::make('created_at')
                    ->schema([
                        DatePicker::make('from')->label(__('dberp.fields.date_from')),
                        DatePicker::make('until')->label(__('dberp.fields.date_until')),
                    ])
                    ->query(function (Builder $query, array $data): Builder {
                        return $query
                            ->when($data['from'] ?? null, fn (Builder $builder, $date): Builder => $builder->whereDate('created_at', '>=', $date))
                            ->when($data['until'] ?? null, fn (Builder $builder, $date): Builder => $builder->whereDate('created_at', '<=', $date));
                    }),
            ])
            ->headerActions([
                static::makeExportAction('integration-sync-log'),
            ])
            ->toolbarActions([
                BulkActionGroup::make([
                    BulkAction::make('retry_selected')
                        ->label(__('dberp.actions.retry_failed_selected'))
                        ->modalDescription(__('dberp.integration_ui.sync_retry_confirmation'))
                        ->requiresConfirmation()
                        ->visible(fn (): bool => app(DberpPermissionService::class)->allows(Auth::user(), DberpPermissionService::MANAGE_INTEGRATION_RETRY_HANDLING))
                        ->action(function (EloquentCollection $records): void {
                            $successCount = 0;
                            $failedCount = 0;

                            foreach ($records as $record) {
                                try {
                                    app(DbshopIntegrationService::class)->retrySyncLog($record);
                                    $successCount++;
                                } catch (\Throwable) {
                                    $failedCount++;
                                }
                            }

                            Notification::make()
                                ->title(__('dberp.integration_ui.sync_retry_bulk_title', [
                                    'success' => $successCount,
                                    'failed' => $failedCount,
                                ]))
                                ->success()
                                ->send();
                        }),
                ]),
            ])
            ->checkIfRecordIsSelectableUsing(fn (DberpIntegrationSyncLog $record): bool => in_array($record->status, [IntegrationSyncStatus::Failed->value, IntegrationSyncStatus::Skipped->value], true))
            ->recordActions([
                Action::make('retry')
                    ->label(__('dberp.actions.retry_sync'))
                    ->modalDescription(__('dberp.integration_ui.sync_retry_confirmation'))
                    ->requiresConfirmation()
                    ->visible(fn (DberpIntegrationSyncLog $record): bool => in_array($record->status, ['failed', 'skipped'], true)
                        && app(DberpPermissionService::class)->allows(Auth::user(), DberpPermissionService::MANAGE_INTEGRATION_RETRY_HANDLING))
                    ->action(function (DberpIntegrationSyncLog $record): void {
                        app(DbshopIntegrationService::class)->retrySyncLog($record);

                        Notification::make()->title(__('dberp.notifications.completed'))->success()->send();
                    }),
            ]);
    }

    public static function canViewAny(): bool
    {
        return static::canAccessIntegrationCenter()
            && static::allowsPermission(DberpPermissionService::VIEW_INTEGRATION_SYNC_LOG);
    }

    public static function canView(Model $record): bool
    {
        return static::canViewAny();
    }

    public static function canCreate(): bool
    {
        return false;
    }

    public static function canEdit(Model $record): bool
    {
        return false;
    }

    public static function canDelete(Model $record): bool
    {
        return false;
    }

    public static function getPages(): array
    {
        return ['index' => ListDberpIntegrationSyncLogs::route('/')];
    }

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

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

    public static function getModelLabel(): string
    {
        return __('dberp.resources.integration_sync_log.label');
    }

    public static function getPluralModelLabel(): string
    {
        return __('dberp.resources.integration_sync_log.plural');
    }

    private static function integrationSystemLabel(?string $state): string
    {
        if ($state === null || $state === '') {
            return '—';
        }

        $options = __('dberp.integration_ui.source_system_options');

        if (is_array($options) && isset($options[$state])) {
            return (string) $options[$state];
        }

        return $state;
    }

    private static function formatRelatedModel(DberpIntegrationSyncLog $record): string
    {
        $relatedModel = $record->relatedModel;

        if (! $relatedModel instanceof Model) {
            return '—';
        }

        $typeLabel = DberpAuditDisplay::auditableTypeLabel($relatedModel::class);

        $segments = array_filter([
            method_exists($relatedModel, 'getKey') ? (string) $relatedModel->getKey() : null,
            $relatedModel->getAttribute('code'),
            $relatedModel->getAttribute('name'),
        ], static fn ($value): bool => is_scalar($value) && (string) $value !== '');

        if ($segments === []) {
            return $typeLabel;
        }

        return $typeLabel.' / '.implode(' / ', array_map(static fn ($value): string => (string) $value, $segments));
    }
}
