<?php

declare(strict_types=1);

namespace App\Filament\Resources\DberpStocktakeDifferences;

use App\Business\Inventory\Enums\InventoryDocumentStatus;
use App\Business\Inventory\Enums\StocktakeDifferenceStatus;
use App\Filament\Concerns\InteractsWithDberpPermissions;
use App\Filament\Contracts\DberpFilamentFormEditability;
use App\Filament\Resources\DberpStocktakeDifferences\Pages\EditDberpStocktakeDifference;
use App\Filament\Resources\DberpStocktakeDifferences\Pages\ListDberpStocktakeDifferences;
use App\Models\DberpStocktakeDifference;
use App\Services\DberpPermissionService;
use App\Support\DberpDocumentLineSpecPresentation;
use App\Support\DberpNumberFormatter;
use App\Support\DberpProductSkuSelectOptions;
use BackedEnum;
use Filament\Actions\EditAction;
use Filament\Forms\Components\DateTimePicker;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Resources\Resource;
use Filament\Schemas\Components\Section;
use Filament\Schemas\Schema;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Table;
use Illuminate\Contracts\Support\Htmlable;
use Illuminate\Database\Eloquent\Model;
use UnitEnum;

class DberpStocktakeDifferenceResource extends Resource implements DberpFilamentFormEditability
{
    use InteractsWithDberpPermissions;

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

    protected static ?string $recordTitleAttribute = 'product_sku_name';

    protected static ?int $navigationSort = 80;

    public static function isRecordFormEditableForFilament(Model $record): bool
    {
        return $record instanceof DberpStocktakeDifference
            && in_array($record->status, [
                StocktakeDifferenceStatus::Pending->value,
                StocktakeDifferenceStatus::Reviewed->value,
            ], true);
    }

    public static function form(Schema $schema): Schema
    {
        return $schema->components([
            Section::make(__('dberp.resources.stocktake_difference.label'))
                ->schema([
                    Select::make('stocktake_order_id')
                        ->label(__('dberp.fields.stocktake_order'))
                        ->relationship('stocktakeOrder', 'code')
                        ->disabled()
                        ->dehydrated(false),
                    DberpProductSkuSelectOptions::configureInventoryProductRelationshipSelect(
                        Select::make('product_id')
                            ->label(__('dberp.fields.product')),
                    )->disabled()->dehydrated(false),
                    Select::make('warehouse_id')
                        ->label(__('dberp.fields.warehouse'))
                        ->relationship('warehouse', 'name')
                        ->disabled()
                        ->dehydrated(false),
                    TextInput::make('book_quantity')
                        ->label(__('dberp.fields.book_quantity'))
                        ->disabled(),
                    TextInput::make('actual_quantity')
                        ->label(__('dberp.fields.actual_quantity'))
                        ->disabled(),
                    TextInput::make('difference_quantity')
                        ->label(__('dberp.fields.difference_quantity'))
                        ->disabled(),
                    Select::make('result_type')
                        ->label(__('dberp.fields.result_type'))
                        ->options(__('dberp.options.stocktake_result_type'))
                        ->disabled(),
                    Select::make('status')
                        ->label(__('dberp.fields.difference_status'))
                        ->options(StocktakeDifferenceStatus::options())
                        ->disabled(),
                    Select::make('reason_code')
                        ->label(__('dberp.fields.reason_code'))
                        ->options(__('dberp.options.stocktake_difference_reason_code')),
                    Textarea::make('reason_detail')
                        ->label(__('dberp.fields.reason_detail'))
                        ->rows(3)
                        ->columnSpanFull(),
                    Select::make('resolution_type')
                        ->label(__('dberp.fields.resolution_type'))
                        ->options(__('dberp.options.stocktake_difference_resolution_type')),
                    Textarea::make('resolution_remark')
                        ->label(__('dberp.fields.resolution_remark'))
                        ->rows(3)
                        ->columnSpanFull(),
                    DateTimePicker::make('handled_at')
                        ->label(__('dberp.fields.handled_at'))
                        ->disabled(),
                ])
                ->columns(3),
        ]);
    }

    public static function table(Table $table): Table
    {
        return $table
            ->modifyQueryUsing(fn ($query) => $query->with(DberpDocumentLineSpecPresentation::eagerLoadsForDocumentLines(['stocktakeOrder'])))
            ->defaultSort('created_at', 'desc')
            ->columns([
                TextColumn::make('stocktakeOrder.code')->label(__('dberp.fields.stocktake_order'))->searchable(),
                TextColumn::make('stocktakeOrder.status')
                    ->label(__('dberp.fields.stocktake_order_status'))
                    ->badge()
                    ->formatStateUsing(fn (?string $state): string => InventoryDocumentStatus::tryFrom((string) $state)?->label() ?? (string) $state)
                    ->color(fn (?string $state): string => match ($state) {
                        InventoryDocumentStatus::Voided->value => 'danger',
                        InventoryDocumentStatus::Effective->value => 'success',
                        InventoryDocumentStatus::Draft->value => 'gray',
                        default => 'gray',
                    }),
                TextColumn::make('product.code')->label(__('dberp.fields.product_code'))->searchable(),
                TextColumn::make('product.name')->label(__('dberp.fields.product_name'))->searchable(),
                TextColumn::make('document_line_spec_summary')
                    ->label(__('dberp.fields.document_line_product_spec_combo'))
                    ->state(fn (Model $record): string => DberpDocumentLineSpecPresentation::lineSpecSummary($record))
                    ->wrap(),
                TextColumn::make('document_line_spec_code')
                    ->label(__('dberp.fields.document_line_spec_code'))
                    ->state(fn (Model $record): string => DberpDocumentLineSpecPresentation::lineSpecCode($record)),
                TextColumn::make('document_line_spec_abstract')
                    ->label(__('dberp.fields.document_line_spec_summary'))
                    ->state(fn (Model $record): string => DberpDocumentLineSpecPresentation::lineSpecAbstract($record))
                    ->wrap()
                    ->toggleable(isToggledHiddenByDefault: true),
                TextColumn::make('warehouse.name')->label(__('dberp.fields.warehouse')),
                TextColumn::make('difference_quantity')->label(__('dberp.fields.difference_quantity'))->formatStateUsing(fn ($state): string => DberpNumberFormatter::quantity($state)),
                TextColumn::make('result_type')
                    ->label(__('dberp.fields.result_type'))
                    ->badge()
                    ->formatStateUsing(fn (?string $state): string => __('dberp.options.stocktake_result_type')[$state] ?? (string) $state),
                TextColumn::make('status')
                    ->label(__('dberp.fields.difference_status'))
                    ->badge()
                    ->formatStateUsing(fn (?string $state): string => StocktakeDifferenceStatus::options()[$state] ?? (string) $state),
                TextColumn::make('reason_code')
                    ->label(__('dberp.fields.reason_code'))
                    ->formatStateUsing(fn (?string $state): string => __('dberp.options.stocktake_difference_reason_code')[$state] ?? '未填写'),
                TextColumn::make('handled_at')->label(__('dberp.fields.handled_at'))->dateTime(),
            ])
            ->filters([
                SelectFilter::make('status')->label(__('dberp.fields.difference_status'))->options(StocktakeDifferenceStatus::options()),
                SelectFilter::make('result_type')->label(__('dberp.fields.result_type'))->options(__('dberp.options.stocktake_result_type')),
                SelectFilter::make('warehouse_id')->label(__('dberp.fields.warehouse'))->relationship('warehouse', 'name'),
                DberpProductSkuSelectOptions::configureProductRelationshipTableFilter(
                    SelectFilter::make('product_id')->label(__('dberp.fields.product')),
                ),
                SelectFilter::make('reason_code')->label(__('dberp.fields.reason_code'))->options(__('dberp.options.stocktake_difference_reason_code')),
            ])
            ->recordActions([
                EditAction::make()
                    ->visible(fn (Model $record): bool => static::isRecordFormEditableForFilament($record) && static::canEdit($record)),
            ]);
    }

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

    public static function canViewAny(): bool
    {
        return static::allowsAnyPermission([
            DberpPermissionService::VIEW_STOCKTAKE_DIFFERENCE,
            DberpPermissionService::HANDLE_STOCKTAKE_DIFFERENCE,
            DberpPermissionService::CONFIRM_STOCKTAKE_DIFFERENCE,
        ]);
    }

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

    public static function canEdit(Model $record): bool
    {
        return static::allowsAnyPermission([
            DberpPermissionService::HANDLE_STOCKTAKE_DIFFERENCE,
            DberpPermissionService::CONFIRM_STOCKTAKE_DIFFERENCE,
        ]);
    }

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

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

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

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

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