<?php

declare(strict_types=1);

namespace App\Filament\Resources\DberpSupplierPerformances;

use App\Business\Report\PurchaseReportService;
use App\Filament\Concerns\InteractsWithDberpPermissions;
use App\Filament\Resources\Concerns\HasDberpExportAction;
use App\Filament\Resources\DberpPurchaseExceptions\DberpPurchaseExceptionResource;
use App\Filament\Resources\DberpPurchaseOrders\DberpPurchaseOrderResource;
use App\Filament\Resources\DberpPurchasePriceReferences\DberpPurchasePriceReferenceResource;
use App\Filament\Resources\DberpPurchaseReturns\DberpPurchaseReturnResource;
use App\Filament\Resources\DberpSupplierPerformances\Pages\ListDberpSupplierPerformances;
use App\Models\DberpEmployee;
use App\Models\DberpProductCategory;
use App\Models\DberpSupplier;
use App\Services\DberpPermissionService;
use App\Support\DberpFilamentMasterDataSelectOptions;
use App\Support\DberpNumberFormatter;
use App\Support\DberpProductSkuSelectOptions;
use App\Support\DberpPurchaseStatisticsFilamentSupport;
use App\Support\DberpSupplierPerformanceFilamentSupport;
use BackedEnum;
use Filament\Actions\Action;
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 DberpSupplierPerformanceResource extends Resource
{
    use HasDberpExportAction;
    use InteractsWithDberpPermissions;

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

    protected static ?string $recordTitleAttribute = 'name';

    protected static ?int $navigationSort = 130;

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

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

    public static function table(Table $table): Table
    {
        $filterQueryPassthrough = fn (Builder $query, array $data): Builder => $query;

        return $table
            ->columns([
                TextColumn::make('code')->label(__('dberp.fields.supplier_code'))->searchable(),
                TextColumn::make('name')->label(__('dberp.fields.supplier_name'))->searchable(),
                TextColumn::make('order_count')->label(__('dberp.fields.order_count'))->numeric(),
                TextColumn::make('purchase_amount')->label(__('dberp.fields.purchase_amount'))->formatStateUsing(fn ($state): string => DberpNumberFormatter::money($state)),
                TextColumn::make('avg_lead_time_days')->label(__('dberp.fields.avg_lead_time_days'))->numeric(),
                TextColumn::make('exception_count_30d')->label(__('dberp.fields.exception_count_30d'))->numeric(),
                TextColumn::make('effective_receipt_count')->label(__('dberp.fields.effective_receipt_count'))->numeric(),
                TextColumn::make('exception_rate_percent')
                    ->label(__('dberp.fields.exception_rate_percent'))
                    ->tooltip(__('dberp.hints.supplier_performance_exception_rate'))
                    ->state(function (DberpSupplier $record): string {
                        $receiptCount = max((int) ($record->effective_receipt_count ?? 0), 1);

                        return (string) (((int) ($record->exception_count_30d ?? 0)) / $receiptCount * 100);
                    })
                    ->formatStateUsing(fn (string $state): string => DberpNumberFormatter::percent($state, false)),
                TextColumn::make('return_order_count_30d')->label(__('dberp.fields.return_order_count_30d'))->numeric(),
                TextColumn::make('active_price_reference_count')->label(__('dberp.fields.active_price_reference_count'))->numeric(),
                TextColumn::make('last_purchase_date')->label(__('dberp.fields.last_purchase_date'))->dateTime(),
                TextColumn::make('latest_reference_date')->label(__('dberp.fields.latest_reference_date'))->date(),
            ])
            ->filters([
                Filter::make('business_time')
                    ->schema([
                        DatePicker::make('from')->label(__('dberp.fields.date_from')),
                        DatePicker::make('until')->label(__('dberp.fields.date_until')),
                    ])
                    ->query($filterQueryPassthrough),
                SelectFilter::make('status')
                    ->label(__('dberp.fields.status'))
                    ->options(__('dberp.options.purchase_order_status'))
                    ->query($filterQueryPassthrough),
                SelectFilter::make('handler_employee_id')
                    ->label(__('dberp.fields.handler_employee'))
                    ->options(fn (): array => DberpEmployee::selectOptionsForFilament())
                    ->searchable()
                    ->preload()
                    ->query($filterQueryPassthrough),
                SelectFilter::make('supplier_id')
                    ->label(__('dberp.fields.supplier'))
                    ->options(fn (): array => DberpSupplier::query()->orderBy('sort_order')->orderBy('id')->pluck('name', 'id')->all())
                    ->query($filterQueryPassthrough),
                SelectFilter::make('category_id')
                    ->label(__('dberp.fields.category'))
                    ->options(fn (): array => DberpProductCategory::query()->orderBy('sort_order')->orderBy('id')->pluck('name', 'id')->all())
                    ->query($filterQueryPassthrough),
                SelectFilter::make('product_id')
                    ->label(__('dberp.fields.product'))
                    ->options(fn (): array => DberpFilamentMasterDataSelectOptions::products())
                    ->query($filterQueryPassthrough),
                DberpProductSkuSelectOptions::configureProductSkuTableFilter(
                    SelectFilter::make('product_sku_id')
                        ->label(__('dberp.fields.product_spec')),
                )->query($filterQueryPassthrough),
                Filter::make('needs_attention')
                    ->label(__('dberp.fields.needs_attention'))
                    ->query(function (Builder $query): Builder {
                        $thresholdDate = now()->subDays(30)->toDateString();

                        return $query->where(function (Builder $builder) use ($thresholdDate): Builder {
                            return $builder
                                ->whereRaw('(
                                    select count(*)
                                    from dberp_purchase_exceptions
                                    where dberp_purchase_exceptions.supplier_id = dberp_suppliers.id
                                      and date(dberp_purchase_exceptions.created_at) >= ?
                                ) >= 2', [$thresholdDate])
                                ->orWhereRaw('(
                                    select count(*)
                                    from dberp_purchase_return_orders
                                    where dberp_purchase_return_orders.supplier_id = dberp_suppliers.id
                                      and dberp_purchase_return_orders.status = ?
                                      and date(dberp_purchase_return_orders.business_time) >= ?
                                ) >= 1', ['effective', $thresholdDate]);
                        });
                    }),
            ])
            ->headerActions([
                static::makeExportAction('supplier-performance'),
            ])
            ->recordActions([
                Action::make('link_purchase_orders')
                    ->label(__('dberp.resources.supplier_performance.link_purchase_orders'))
                    ->url(fn (DberpSupplier $record, ListDberpSupplierPerformances $livewire): string => DberpPurchaseStatisticsFilamentSupport::purchaseOrderIndexUrlForSupplierRanking(
                        $record,
                        is_array($livewire->tableFilters) ? $livewire->tableFilters : [],
                    ))
                    ->visible(fn (): bool => DberpPurchaseOrderResource::canViewAny()),
                Action::make('link_purchase_exceptions')
                    ->label(__('dberp.resources.supplier_performance.link_purchase_exceptions'))
                    ->url(fn (DberpSupplier $record): string => DberpSupplierPerformanceFilamentSupport::purchaseExceptionIndexUrl($record))
                    ->visible(fn (): bool => DberpPurchaseExceptionResource::canViewAny()),
                Action::make('link_purchase_returns')
                    ->label(__('dberp.resources.supplier_performance.link_purchase_returns'))
                    ->url(fn (DberpSupplier $record): string => DberpSupplierPerformanceFilamentSupport::purchaseReturnIndexUrl($record))
                    ->visible(fn (): bool => DberpPurchaseReturnResource::canViewAny()),
                Action::make('link_purchase_price_references')
                    ->label(__('dberp.resources.supplier_performance.link_purchase_price_references'))
                    ->url(fn (DberpSupplier $record): string => DberpSupplierPerformanceFilamentSupport::purchasePriceReferenceIndexUrl($record))
                    ->visible(fn (): bool => DberpPurchasePriceReferenceResource::canViewAny()),
            ])
            ->defaultSort('exception_count_30d', 'desc');
    }

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

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

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

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

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

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

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