<?php

declare(strict_types=1);

/**
 * 本文件属于 DBErp 进销存系统。
 *
 * 版权所有 © 2026 北京珑大钜商科技有限公司。保留所有权利。
 *
 * 未经官方授权，不得删除、篡改或隐藏本文件中的版权声明、产品标识与来源信息。
 * 商业授权、官方更新与技术支持服务，请以珑大官方支持中心记录为准。
 *
 * @link https://support.loongdom.cn
 * @see  https://www.dberp.com.cn
 */

namespace App\Filament\Resources\DberpProducts\RelationManagers;

use App\Business\Product\ProductSkuCombinationGenerator;
use App\Business\Product\ProductSkuFormService;
use App\Business\Product\ProductSkuLifecycleService;
use App\Filament\Resources\DberpProducts\DberpProductResource;
use App\Filament\Support\DberpFilamentNumberFields;
use App\Filament\Support\DberpProductSpecMatrixRebuildAction;
use App\Models\DberpProduct;
use App\Models\DberpProductSku;
use App\Models\DberpUnit;
use App\Support\DberpNumberFormatter;
use App\Support\PluginIntegration\BarcodeLabelFilamentBridge;
use Filament\Actions\Action;
use Filament\Actions\CreateAction;
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\Notifications\Notification;
use Filament\Resources\RelationManagers\RelationManager;
use Filament\Schemas\Components\Group;
use Filament\Schemas\Schema;
use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Validation\ValidationException;

class ProductSkusRelationManager extends RelationManager
{
    protected static string $relationship = 'skus';

    private function ownerSpecMatrixReady(): bool
    {
        $product = $this->getOwnerRecord();
        if (! $product instanceof DberpProduct || ! $product->spec_enabled) {
            return false;
        }

        $groups = $product->specGroups()->withCount('specValues')->get();

        return $groups->isNotEmpty() && $groups->every(fn ($g): bool => $g->spec_values_count > 0);
    }

    public static function canViewForRecord(Model $ownerRecord, string $pageClass): bool
    {
        return $ownerRecord instanceof DberpProduct && $ownerRecord->spec_enabled;
    }

    public static function getTitle(Model $ownerRecord, string $pageClass): string
    {
        return __('dberp.relations.product_spec_combos');
    }

    protected static function getModelLabel(): ?string
    {
        return __('dberp.relations.product_spec_combo');
    }

    protected static function getPluralModelLabel(): ?string
    {
        return __('dberp.relations.product_spec_combos');
    }

    public function form(Schema $schema): Schema
    {
        $product = $this->getOwnerRecord();
        if (! $product instanceof DberpProduct) {
            return $schema->components([]);
        }

        $product->loadMissing(['specGroups.specValues']);

        $components = [];

        if ($product->spec_enabled && $product->specGroups->isNotEmpty()) {
            $pickFields = [];
            foreach ($product->specGroups->sortBy(fn ($g): array => [(int) $g->sort_order, $g->id]) as $group) {
                $pickFields[] = Select::make('pick_spec_g_'.$group->getKey())
                    ->label($group->name)
                    ->options(
                        $group->specValues
                            ->sortBy(fn ($v): array => [(int) $v->sort_order, $v->id])
                            ->mapWithKeys(fn (Model $v): array => [$v->getKey() => $v->getAttribute('value_label')])
                            ->all(),
                    )
                    ->searchable()
                    ->preload()
                    ->required()
                    ->native(false);
            }

            $components[] = Group::make()
                ->schema($pickFields)
                ->columns(2)
                ->columnSpanFull();
        }

        $components = array_merge($components, [
            TextInput::make('sku_code')
                ->label(__('dberp.fields.spec_combo_code'))
                ->maxLength(64)
                ->helperText(__('dberp.hints.spec_combo_code'))
                ->unique(ignoreRecord: true)
                ->validationMessages([
                    'unique' => (string) __('dberp.validation.product_spec_combo_code_unique'),
                ]),
            TextInput::make('barcode')
                ->label(__('dberp.fields.barcode'))
                ->maxLength(64)
                ->unique(ignoreRecord: true)
                ->validationMessages([
                    'unique' => (string) __('dberp.validation.product_barcode_unique_non_empty'),
                ]),
            TextInput::make('spec_text')
                ->label(__('dberp.fields.spec_combo_summary'))
                ->maxLength(512),
            DberpFilamentNumberFields::moneyInput(
                TextInput::make('cost_price')
                    ->label(__('dberp.fields.cost_price'))
                    ->default(0),
                withHelperText: false,
                minValue: 0.0,
            ),
            DberpFilamentNumberFields::moneyInput(
                TextInput::make('sales_price')
                    ->label(__('dberp.fields.sales_price'))
                    ->default(0),
                withHelperText: false,
                minValue: 0.0,
            ),
            Select::make('unit_id')
                ->label(__('dberp.fields.unit_override'))
                ->helperText(__('dberp.hints.product_sku_unit_override'))
                ->options(fn (): array => DberpUnit::query()
                    ->where('is_enabled', true)
                    ->orderBy('sort_order')
                    ->orderBy('id')
                    ->pluck('name', 'id')
                    ->all())
                ->searchable()
                ->preload()
                ->nullable(),
            TextInput::make('sort_order')
                ->label(__('dberp.fields.sort_order'))
                ->numeric()
                ->default(0)
                ->required(),
            Toggle::make('is_enabled')
                ->label(__('dberp.fields.is_enabled'))
                ->default(true),
            Toggle::make('is_default')
                ->label(__('dberp.fields.default_spec_combo'))
                ->helperText(__('dberp.hints.default_spec_combo')),
            Textarea::make('remark')
                ->label(__('dberp.fields.remark'))
                ->rows(2)
                ->columnSpanFull(),
        ]);

        return $schema->components($components);
    }

    public function table(Table $table): Table
    {
        return $table
            ->description(function (): ?string {
                $product = $this->getOwnerRecord();
                if (! $product instanceof DberpProduct || ! $product->spec_enabled) {
                    return null;
                }

                if (! $this->ownerSpecMatrixReady()) {
                    return (string) __('dberp.messages.spec_matrix_not_ready');
                }

                return (string) __('dberp.hints.spec_combos_lifecycle');
            })
            ->recordTitleAttribute('spec_text')
            ->defaultSort('sort_order', 'asc')
            ->columns([
                TextColumn::make('sku_code')
                    ->label(__('dberp.fields.spec_combo_code'))
                    ->searchable(),
                TextColumn::make('barcode')
                    ->label(__('dberp.fields.barcode')),
                TextColumn::make('spec_text')
                    ->label(__('dberp.fields.spec_combo_summary'))
                    ->limit(40),
                TextColumn::make('cost_price')
                    ->label(__('dberp.fields.cost_price'))
                    ->formatStateUsing(fn ($state): string => DberpNumberFormatter::costPrice($state)),
                TextColumn::make('sales_price')
                    ->label(__('dberp.fields.sales_price'))
                    ->formatStateUsing(fn ($state): string => DberpNumberFormatter::price($state)),
                IconColumn::make('is_default')
                    ->label(__('dberp.fields.default_spec_combo'))
                    ->boolean(),
                IconColumn::make('is_enabled')
                    ->label(__('dberp.fields.is_enabled'))
                    ->boolean(),
                TextColumn::make('sort_order')
                    ->label(__('dberp.fields.sort_order'))
                    ->sortable(),
            ])
            ->headerActions([
                DberpProductSpecMatrixRebuildAction::make(
                    fn (): ?DberpProduct => $this->getOwnerRecord() instanceof DberpProduct ? $this->getOwnerRecord() : null,
                    fn (): mixed => $this->redirect(DberpProductResource::getUrl('edit', ['record' => $this->getOwnerRecord()])),
                ),
                Action::make('generateSpecCombinations')
                    ->label(__('dberp.actions.generate_spec_combinations'))
                    ->visible(fn (): bool => $this->ownerSpecMatrixReady())
                    ->requiresConfirmation()
                    ->modalDescription(__('dberp.hints.generate_spec_combinations'))
                    ->action(function (): void {
                        $product = $this->getOwnerRecord()->fresh(['specGroups.specValues']);
                        if (! $product instanceof DberpProduct) {
                            return;
                        }

                        $created = app(ProductSkuCombinationGenerator::class)->generateMissing($product);

                        Notification::make()
                            ->title(__('dberp.notifications.spec_combinations_generated', ['count' => $created]))
                            ->success()
                            ->send();
                    }),
                CreateAction::make()
                    ->visible(fn (): bool => $this->ownerSpecMatrixReady())
                    ->using(function (array $data): DberpProductSku {
                        return app(ProductSkuFormService::class)->createSkuFromRelationForm(
                            $this->getOwnerRecord()->fresh(),
                            $data,
                        );
                    }),
            ])
            ->toolbarActions([
                ...BarcodeLabelFilamentBridge::skuRelationToolbarActions(
                    fn (DberpProductSku $record): bool => DberpProductResource::canView($this->getOwnerRecord()),
                ),
            ])
            ->recordActions([
                ...BarcodeLabelFilamentBridge::skuRecordActions(
                    fn (DberpProductSku $record): bool => DberpProductResource::canView($this->getOwnerRecord()),
                ),
                EditAction::make()
                    ->mutateRecordDataUsing(function (array $data): array {
                        $sku = DberpProductSku::query()->with('skuSpecAssignments')->find($data['id'] ?? null);
                        if ($sku === null) {
                            return $data;
                        }

                        foreach ($sku->skuSpecAssignments as $assignment) {
                            $data['pick_spec_g_'.$assignment->product_spec_group_id] = $assignment->product_spec_value_id;
                        }

                        return $data;
                    })
                    ->using(function (array $data, Model $record): void {
                        app(ProductSkuFormService::class)->updateSkuFromRelationForm(
                            DberpProductSku::query()->findOrFail($record->getKey()),
                            $this->getOwnerRecord()->fresh(),
                            $data,
                        );
                    }),
                Action::make('disableSpecCombo')
                    ->label(__('dberp.actions.disable_spec_combo'))
                    ->color('warning')
                    ->visible(fn (DberpProductSku $record): bool => $record->is_enabled)
                    ->requiresConfirmation()
                    ->action(function (DberpProductSku $record): void {
                        try {
                            $record->update(['is_enabled' => false]);
                        } catch (ValidationException $exception) {
                            Notification::make()
                                ->title((string) __('dberp.notifications.operation_blocked'))
                                ->body(collect($exception->errors())->flatten()->first())
                                ->danger()
                                ->send();

                            throw $exception;
                        }
                    }),
                DeleteAction::make('deleteSpecCombo')
                    ->label(__('dberp.actions.delete_spec_combo'))
                    ->modalHeading(__('dberp.headings.delete_spec_combo'))
                    ->modalDescription(__('dberp.hints.delete_spec_combo'))
                    ->visible(fn (DberpProductSku $record): bool => app(ProductSkuLifecycleService::class)->canPhysicallyDeleteSpecCombo($record))
                    ->action(function (DberpProductSku $record): void {
                        try {
                            app(ProductSkuLifecycleService::class)->physicallyDeleteSpecComboIfAllowed($record);

                            Notification::make()
                                ->title((string) __('dberp.notifications.spec_combo_deleted'))
                                ->success()
                                ->send();
                        } catch (ValidationException $exception) {
                            Notification::make()
                                ->title((string) __('dberp.notifications.operation_blocked'))
                                ->body(collect($exception->errors())->flatten()->first())
                                ->danger()
                                ->send();

                            throw $exception;
                        }
                    }),
            ]);
    }
}
