<?php

declare(strict_types=1);

namespace App\Filament\Resources\DberpRegions;

use App\Business\MasterData\DberpRegionAddressService;
use App\Business\MasterData\DberpRegionSource;
use App\Business\MasterData\Enums\RegionLevel;
use App\Filament\Concerns\InteractsWithDberpPermissions;
use App\Filament\Resources\DberpRegions\Pages\CreateDberpRegion;
use App\Filament\Resources\DberpRegions\Pages\EditDberpRegion;
use App\Filament\Resources\DberpRegions\Pages\ListDberpRegions;
use App\Filament\Support\DberpFilamentRelationshipSelectLimits;
use App\Models\DberpRegion;
use App\Services\DberpPermissionService;
use App\Support\DberpFilamentSearchableSelectOptions;
use App\Support\DberpProductSkuSelectOptions;
use BackedEnum;
use Filament\Actions\BulkAction;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteAction;
use Filament\Actions\EditAction;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Toggle;
use Filament\Resources\Resource;
use Filament\Schemas\Components\Section;
use Filament\Schemas\Schema;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Columns\ToggleColumn;
use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Filters\TernaryFilter;
use Filament\Tables\Table;
use Illuminate\Contracts\Support\Htmlable;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Schema as SchemaFacade;
use UnitEnum;

class DberpRegionResource extends Resource
{
    use InteractsWithDberpPermissions;

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

    protected static ?string $recordTitleAttribute = 'name';

    protected static ?int $navigationSort = 25;

    public static function form(Schema $schema): Schema
    {
        return static::editForm($schema);
    }

    public static function editForm(Schema $schema): Schema
    {
        return $schema
            ->components([
                Section::make(__('dberp.sections.region_basic'))
                    ->description(__('dberp.hints.region_import_update_policy'))
                    ->schema([
                        Select::make('level')
                            ->label(__('dberp.fields.region_level'))
                            ->options(RegionLevel::options())
                            ->disabled(),
                        TextInput::make('name')
                            ->label(__('dberp.fields.region_name'))
                            ->required()
                            ->maxLength(160),
                        TextInput::make('short_name')
                            ->label(__('dberp.fields.region_short_name'))
                            ->maxLength(120),
                        TextInput::make('region_code')
                            ->label(__('dberp.fields.region_code'))
                            ->disabled(),
                        TextInput::make('external_code')
                            ->label(__('dberp.fields.external_code'))
                            ->disabled(),
                        TextInput::make('sort_order')
                            ->label(__('dberp.fields.sort_order'))
                            ->numeric()
                            ->required()
                            ->minValue(0),
                        Toggle::make('is_enabled')
                            ->label(__('dberp.fields.is_enabled'))
                            ->helperText(__('dberp.hints.region_disable_scope')),
                    ])
                    ->columns(2),
                Section::make(__('dberp.sections.region_hierarchy'))
                    ->schema([
                        TextInput::make('depth')
                            ->label(__('dberp.fields.region_depth'))
                            ->disabled(),
                        Toggle::make('is_leaf')
                            ->label(__('dberp.fields.is_leaf'))
                            ->disabled(),
                        Select::make('source')
                            ->label(__('dberp.fields.region_source'))
                            ->options(fn ($livewire): array => static::regionSourceSelectOptions($livewire->getRecord()?->source))
                            ->disabled(),
                        TextInput::make('merger_name')
                            ->label(__('dberp.fields.merger_name'))
                            ->disabled()
                            ->columnSpanFull(),
                        TextInput::make('path')
                            ->label(__('dberp.fields.region_path'))
                            ->disabled()
                            ->helperText(__('dberp.hints.region_parent_change_restricted'))
                            ->columnSpanFull(),
                    ])
                    ->columns(2),
            ]);
    }

    public static function manualCreateForm(Schema $schema): Schema
    {
        $fields = [
            DberpFilamentSearchableSelectOptions::configure(
                Select::make('parent_id')
                    ->label(__('dberp.fields.parent_region'))
                    ->nullable()
                    ->helperText(__('dberp.hints.region_manual_create_parent')),
                fn (): int => static::enabledManualParentRegionCount(),
                fn (): array => static::manualParentRegionOptions(''),
                fn (string $search): array => static::manualParentRegionOptions($search),
                function ($value): ?string {
                    if ($value === null || $value === '') {
                        return null;
                    }

                    $region = DberpRegion::query()->find((int) $value);

                    if (! $region instanceof DberpRegion) {
                        return null;
                    }

                    return static::manualParentOptionLabel($region);
                },
            ),
            TextInput::make('name')
                ->label(__('dberp.fields.region_name'))
                ->required()
                ->maxLength(160),
            TextInput::make('short_name')
                ->label(__('dberp.fields.region_short_name'))
                ->maxLength(120),
            TextInput::make('sort_order')
                ->label(__('dberp.fields.sort_order'))
                ->numeric()
                ->required()
                ->minValue(0),
            Toggle::make('is_enabled')
                ->label(__('dberp.fields.region_status'))
                ->default(true)
                ->helperText(__('dberp.hints.region_manual_create_status')),
        ];

        if (SchemaFacade::hasColumn((new DberpRegion)->getTable(), 'remark')) {
            $fields[] = Textarea::make('remark')
                ->label(__('dberp.fields.remark'))
                ->rows(3)
                ->maxLength(500)
                ->columnSpanFull();
        }

        return $schema
            ->components([
                Section::make(__('dberp.sections.region_manual_create'))
                    ->description(__('dberp.hints.region_manual_create_intro'))
                    ->schema($fields)
                    ->columns(2),
            ]);
    }

    public static function table(Table $table): Table
    {
        return $table
            ->columns([
                TextColumn::make('name')
                    ->label(__('dberp.fields.region_name'))
                    ->formatStateUsing(fn (string $state, DberpRegion $record): string => str_repeat('　', max(0, $record->depth - 1)).$state)
                    ->description(fn (DberpRegion $record): string => app('App\\Business\\MasterData\\DberpRegionAddressService')->formatRegionPath($record->merger_name))
                    ->wrap()
                    ->searchable(),
                TextColumn::make('short_name')
                    ->label(__('dberp.fields.region_short_name'))
                    ->placeholder('-')
                    ->searchable()
                    ->toggleable(isToggledHiddenByDefault: true),
                TextColumn::make('region_code')
                    ->label(__('dberp.fields.region_code'))
                    ->toggleable(isToggledHiddenByDefault: true)
                    ->searchable(),
                TextColumn::make('external_code')
                    ->label(__('dberp.fields.external_code'))
                    ->placeholder('-')
                    ->toggleable(isToggledHiddenByDefault: true)
                    ->searchable(),
                TextColumn::make('country_code')
                    ->label(__('dberp.fields.country'))
                    ->formatStateUsing(fn (string $state): string => static::countryLabel($state)),
                TextColumn::make('source')
                    ->label(__('dberp.fields.region_source'))
                    ->formatStateUsing(fn (?string $state): string => DberpRegionSource::labelForStoredSource($state))
                    ->toggleable(isToggledHiddenByDefault: true),
                TextColumn::make('level')
                    ->label(__('dberp.fields.region_level'))
                    ->badge()
                    ->formatStateUsing(fn (string $state): string => RegionLevel::tryFrom($state)?->label() ?? __('dberp.options.region_level.other')),
                TextColumn::make('parent.name')
                    ->label(__('dberp.fields.parent_region'))
                    ->placeholder('-'),
                TextColumn::make('is_leaf')
                    ->label(__('dberp.fields.region_selection_status'))
                    ->badge()
                    ->formatStateUsing(fn (bool $state): string => $state ? __('dberp.messages.region_final_selectable') : __('dberp.messages.region_not_final_selectable'))
                    ->color(fn (bool $state): string => $state ? 'success' : 'gray'),
                TextColumn::make('children_count')
                    ->label(__('dberp.fields.children_count'))
                    ->counts('children')
                    ->alignCenter(),
                TextColumn::make('reference_count')
                    ->label(__('dberp.fields.reference_count'))
                    ->state(fn (DberpRegion $record): int => (int) ($record->customers_count ?? 0) + (int) ($record->suppliers_count ?? 0) + (int) ($record->warehouses_count ?? 0))
                    ->description(fn (DberpRegion $record): string => app('App\\Business\\MasterData\\DberpRegionGovernanceService')->usageSummary($record)),
                ToggleColumn::make('is_enabled')
                    ->label(__('dberp.fields.region_status')),
                TextColumn::make('sort_order')
                    ->label(__('dberp.fields.sort_order'))
                    ->sortable(),
                TextColumn::make('merger_name')
                    ->label(__('dberp.fields.merger_name'))
                    ->formatStateUsing(fn (?string $state): string => app('App\\Business\\MasterData\\DberpRegionAddressService')->formatRegionPath($state))
                    ->toggleable(isToggledHiddenByDefault: true),
                TextColumn::make('updated_at')
                    ->label(__('dberp.fields.updated_at'))
                    ->dateTime()
                    ->sortable()
                    ->toggleable(isToggledHiddenByDefault: true),
            ])
            ->filters([
                ...static::regionListCountryFilters(),
                SelectFilter::make('level')
                    ->label(__('dberp.fields.region_level'))
                    ->options(RegionLevel::options()),
                TernaryFilter::make('is_enabled')
                    ->label(__('dberp.fields.is_enabled')),
            ])
            ->recordActions([
                EditAction::make()
                    ->visible(fn (): bool => static::allowsPermission(DberpPermissionService::EDIT_MASTER_REGION)),
                DeleteAction::make()
                    ->visible(fn (): bool => static::allowsPermission(DberpPermissionService::DELETE_MASTER_REGION)),
            ])
            ->toolbarActions([
                BulkActionGroup::make([
                    BulkAction::make('enable_selected')
                        ->label(__('dberp.actions.enable'))
                        ->requiresConfirmation()
                        ->visible(fn (): bool => static::allowsPermission(DberpPermissionService::EDIT_MASTER_REGION))
                        ->action(fn (Collection $records) => app('App\\Business\\MasterData\\DberpRegionGovernanceService')->enableRecords($records)),
                    BulkAction::make('disable_selected')
                        ->label(__('dberp.actions.disable'))
                        ->requiresConfirmation()
                        ->visible(fn (): bool => static::allowsPermission(DberpPermissionService::EDIT_MASTER_REGION))
                        ->action(fn (Collection $records) => app('App\\Business\\MasterData\\DberpRegionGovernanceService')->disableRecords($records)),
                ]),
            ]);
    }

    public static function canViewAny(): bool
    {
        return static::allowsPermission(DberpPermissionService::VIEW_MASTER_REGION);
    }

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

    public static function canCreate(): bool
    {
        return static::allowsPermission(DberpPermissionService::CREATE_MASTER_REGION);
    }

    public static function canEdit(Model $record): bool
    {
        return static::allowsPermission(DberpPermissionService::EDIT_MASTER_REGION);
    }

    public static function canDelete(Model $record): bool
    {
        if (! static::allowsPermission(DberpPermissionService::DELETE_MASTER_REGION)) {
            return false;
        }

        if (! $record instanceof DberpRegion) {
            return false;
        }

        return DberpRegionSource::isManual((string) $record->source);
    }

    public static function getEloquentQuery(): Builder
    {
        return parent::getEloquentQuery()
            ->with('parent')
            ->withCount('children')
            ->withCount('customers')
            ->withCount('suppliers')
            ->withCount('warehouses')
            ->orderBy('country_code')
            ->orderBy('depth')
            ->orderBy('parent_id')
            ->orderBy('sort_order')
            ->orderBy('id');
    }

    public static function getPages(): array
    {
        return [
            'index' => ListDberpRegions::route('/'),
            'create' => CreateDberpRegion::route('/create'),
            'edit' => EditDberpRegion::route('/{record}/edit'),
        ];
    }

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

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

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

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

    /**
     * @return array<int, SelectFilter>
     */
    private static function regionListCountryFilters(): array
    {
        if (! app(DberpRegionAddressService::class)->shouldOfferCountryChoice()) {
            return [];
        }

        return [
            SelectFilter::make('country_code')
                ->label(__('dberp.fields.country'))
                ->options(fn (): array => static::countryFilterOptions()),
        ];
    }

    /**
     * @return array<string, string>
     */
    private static function countryFilterOptions(): array
    {
        $labels = (array) config('dberp.regions.country_labels', []);

        return DberpRegion::query()
            ->distinct()
            ->orderBy('country_code')
            ->pluck('country_code')
            ->mapWithKeys(fn (string $countryCode): array => [$countryCode => $labels[$countryCode] ?? $countryCode])
            ->all();
    }

    private static function countryLabel(string $countryCode): string
    {
        return ((array) config('dberp.regions.country_labels', []))[$countryCode] ?? $countryCode;
    }

    /**
     * @return array<string, string>
     */
    private static function regionSourceSelectOptions(?string $currentSource): array
    {
        $base = __('dberp.options.region_source');

        if (! is_array($base)) {
            $base = [];
        }

        $importSource = (string) config('dberp.regions.china_import.source', 'china_bundled');

        if ($importSource !== '' && ! array_key_exists($importSource, $base)) {
            $base[$importSource] = DberpRegionSource::labelForStoredSource($importSource);
        }

        if ($currentSource === null || $currentSource === '') {
            return $base;
        }

        if (! array_key_exists($currentSource, $base)) {
            return [...$base, $currentSource => DberpRegionSource::labelForStoredSource($currentSource)];
        }

        return $base;
    }

    private static function manualParentOptionLabel(DberpRegion $region): string
    {
        $name = (string) $region->name;

        if (blank($region->merger_name)) {
            return $name;
        }

        $path = app('App\\Business\\MasterData\\DberpRegionAddressService')->formatRegionPath((string) $region->merger_name);

        return $path.' — '.$name;
    }

    private static function enabledManualParentRegionCount(): int
    {
        return static::enabledManualParentRegionQuery()->count();
    }

    /**
     * @return array<int|string, string>
     */
    private static function manualParentRegionOptions(string $search): array
    {
        $search = trim($search);
        $query = static::enabledManualParentRegionQuery();

        if ($search !== '') {
            $like = '%'.str_replace(['%', '_', '\\'], ['\\%', '\\_', '\\\\'], $search).'%';

            $query->where(function (Builder $builder) use ($like): void {
                $builder->where('name', 'like', $like)
                    ->orWhere('region_code', 'like', $like);

                if (SchemaFacade::hasColumn((new DberpRegion)->getTable(), 'merger_name')) {
                    $builder->orWhere('merger_name', 'like', $like);
                }
            });
        }

        if (static::enabledManualParentRegionCount() >= DberpProductSkuSelectOptions::SEARCHABLE_OPTION_THRESHOLD) {
            $query->limit(DberpFilamentRelationshipSelectLimits::PRELOAD_OPTION_LIMIT);
        }

        return $query
            ->get()
            ->mapWithKeys(fn (DberpRegion $region): array => [
                $region->getKey() => static::manualParentOptionLabel($region),
            ])
            ->all();
    }

    /**
     * @return Builder<DberpRegion>
     */
    private static function enabledManualParentRegionQuery(): Builder
    {
        return DberpRegion::query()
            ->where('is_enabled', true)
            ->orderBy('path')
            ->orderBy('id');
    }
}
