<?php

declare(strict_types=1);

namespace App\Filament\Resources\DberpProducts\RelationManagers;

use App\Business\Product\ProductSkuCombinationGenerator;
use App\Business\Product\ProductSkuFormService;
use App\Filament\Support\DberpFilamentNumberFields;
use App\Models\DberpProduct;
use App\Models\DberpProductSku;
use App\Models\DberpUnit;
use App\Support\DberpNumberFormatter;
use Filament\Actions\Action;
use Filament\Actions\CreateAction;
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;

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 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 null;
                }

                return (string) __('dberp.messages.spec_matrix_not_ready');
            })
            ->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([
                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,
                        );
                    }),
            ])
            ->recordActions([
                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 {
                        $record->update(['is_enabled' => false]);
                    }),
            ]);
    }
}
