<?php

declare(strict_types=1);

namespace App\Filament\Resources\DberpCustomerReceivables;

use App\Business\Settlement\Enums\SettlementRecordStatus;
use App\Filament\Concerns\InteractsWithDberpPermissions;
use App\Filament\Resources\DberpCustomerReceivables\Pages\ListDberpCustomerReceivables;
use App\Models\DberpCustomer;
use App\Models\DberpEmployee;
use App\Models\DberpReceivableRecord;
use App\Services\DberpPermissionService;
use App\Support\DberpNumberFormatter;
use BackedEnum;
use Filament\Forms\Components\DatePicker;
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\Model;
use UnitEnum;

class DberpCustomerReceivableResource extends Resource
{
    use InteractsWithDberpPermissions;

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

    protected static ?string $recordTitleAttribute = 'code';

    protected static ?int $navigationSort = 20;

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

    public static function table(Table $table): Table
    {
        return $table
            ->defaultSort('business_date', 'desc')
            ->columns([
                TextColumn::make('code')
                    ->label(__('dberp.fields.receivable_record_code'))
                    ->searchable(),
                TextColumn::make('customer.name')
                    ->label(__('dberp.fields.customer'))
                    ->searchable(),
                TextColumn::make('source_document_no')
                    ->label(__('dberp.fields.source_document_no'))
                    ->searchable(),
                TextColumn::make('handlerEmployee.name')
                    ->label(__('dberp.fields.handler_employee'))
                    ->toggleable(isToggledHiddenByDefault: true),
                TextColumn::make('source_document_status')
                    ->label(__('dberp.fields.order_status'))
                    ->badge()
                    ->formatStateUsing(fn (?string $state): string => __('dberp.options.sales_order_status')[$state] ?? (string) $state),
                TextColumn::make('record_status')
                    ->label(__('dberp.fields.record_status'))
                    ->badge()
                    ->formatStateUsing(fn (?string $state): string => SettlementRecordStatus::tryFrom((string) $state)?->label() ?? (string) $state),
                TextColumn::make('adjusted_amount')
                    ->label(__('dberp.fields.receivable_amount'))
                    ->formatStateUsing(fn ($state): string => DberpNumberFormatter::money($state)),
                TextColumn::make('written_off_amount')
                    ->label(__('dberp.fields.written_off_amount'))
                    ->formatStateUsing(fn ($state): string => DberpNumberFormatter::money($state)),
                TextColumn::make('remaining_amount')
                    ->label(__('dberp.fields.unreceived_amount'))
                    ->formatStateUsing(fn ($state): string => DberpNumberFormatter::money($state)),
                TextColumn::make('due_date')
                    ->label(__('dberp.fields.due_date'))
                    ->date(),
                TextColumn::make('business_date')
                    ->label(__('dberp.fields.business_time'))
                    ->dateTime(),
                TextColumn::make('last_write_off_at')
                    ->label(__('dberp.fields.last_write_off_at'))
                    ->dateTime()
                    ->toggleable(isToggledHiddenByDefault: true),
            ])
            ->filters([
                SelectFilter::make('customer_id')
                    ->label(__('dberp.fields.customer'))
                    ->options(fn (): array => DberpCustomer::query()
                        ->where('is_enabled', true)
                        ->orderBy('sort_order')
                        ->orderBy('id')
                        ->pluck('name', 'id')
                        ->all()),
                SelectFilter::make('record_status')
                    ->label(__('dberp.fields.record_status'))
                    ->options(SettlementRecordStatus::options()),
                SelectFilter::make('handler_employee_id')
                    ->label(__('dberp.fields.handler_employee'))
                    ->options(fn (): array => DberpEmployee::selectOptionsForFilament(
                        fn (Builder $q) => $q->where('is_enabled', true),
                    )),
                SelectFilter::make('attention_status')
                    ->label(__('dberp.fields.attention_status'))
                    ->options(__('dberp.options.settlement_attention_status_receivable'))
                    ->query(function (Builder $query, array $data): Builder {
                        $value = $data['value'] ?? null;

                        return match ($value) {
                            'due_today' => $query->where(function (Builder $builder): void {
                                $builder->whereDate('due_date', now()->toDateString())
                                    ->orWhere(function (Builder $fallback): void {
                                        $fallback->whereNull('due_date')->whereDate('business_date', now()->toDateString());
                                    });
                            }),
                            'due_soon' => $query->where(function (Builder $builder): void {
                                $builder->whereBetween('due_date', [now()->toDateString(), now()->addDays((int) config('dberp.settlement.reminders.due_soon_days', 7))->toDateString()])
                                    ->orWhere(function (Builder $fallback): void {
                                        $fallback->whereNull('due_date')->whereBetween('business_date', [now()->toDateString(), now()->addDays((int) config('dberp.settlement.reminders.due_soon_days', 7))->toDateString()]);
                                    });
                            }),
                            'overdue' => $query->where(function (Builder $builder): void {
                                $builder->whereDate('due_date', '<', now()->toDateString())
                                    ->orWhere(function (Builder $fallback): void {
                                        $fallback->whereNull('due_date')->whereDate('business_date', '<', now()->toDateString());
                                    });
                            }),
                            default => $query,
                        };
                    }),
                Filter::make('business_time_range')
                    ->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('business_date', '>=', $date))
                            ->when($data['until'] ?? null, fn (Builder $builder, $date): Builder => $builder->whereDate('business_date', '<=', $date));
                    }),
            ])
            ->recordActions([]);
    }

    public static function getEloquentQuery(): Builder
    {
        return parent::getEloquentQuery()
            ->with(['customer', 'handlerEmployee'])
            ->where('remaining_amount', '>', 0);
    }

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

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

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

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

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

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

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