<?php

namespace App\Filament\Resources\DelayedGoods\Schemas;

use App\Models\Unit;
use App\Models\Warehouse;
use App\Models\WarehouseStock;
use Filament\Forms\Components\DatePicker;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Toggle;
use Filament\Schemas\Components\Grid;
use Filament\Schemas\Schema;

class DelayedGoodForm
{
    public static function configure(Schema $schema): Schema
    {
        $unmaskQty = function ($state) {
            if (blank($state)) {
                return 0;
            }

            if (is_int($state) || is_float($state)) {
                return $state;
            }

            return (float) str($state)
                ->replace(',', '.')
                ->toString();
        };

        $unmaskMoney = function ($state) {
            if (blank($state)) {
                return 0;
            }

            if (is_int($state) || is_float($state)) {
                return $state;
            }

            return (float) str($state)
                ->replace('.', '')
                ->replace(',', '.')
                ->toString();
        };

        $recalculateTotal = function (callable $get, callable $set) use ($unmaskMoney, $unmaskQty): void {
            $quantity = $unmaskQty($get('quantity'));
            $unitPrice = $unmaskMoney($get('unit_price'));

            $totalAmount = $quantity * $unitPrice;

            $set('total_amount', number_format($totalAmount, 0, ',', '.'));
        };

        $recalculateRemaining = function (callable $get, callable $set) use ($unmaskMoney): void {
            $paidAmount = $unmaskMoney($get('paid_amount'));
            $totalAmount = $unmaskMoney($get('total_amount'));

            $remaining = max(0, $totalAmount - $paidAmount);

            $set('remaining_amount', number_format($remaining, 0, ',', '.'));
        };

        return $schema->components([
            Grid::make(3)
                ->schema([
                    DatePicker::make('stored_date')
                        ->label('Tanggal Penyimpanan')
                        ->default(now())
                        ->required()
                        ->native(false)
                        ->displayFormat('l, d F Y'),

                    Select::make('warehouse_id')
                        ->label('Ambil Dari Gudang')
                        ->relationship('warehouse', 'name')
                        ->searchable()
                        ->preload()
                        ->native(false)
                        ->required()
                        ->live()
                        ->default(fn () => Warehouse::first()?->id),

                    Select::make('customer_id')
                        ->label('Pelanggan')
                        ->relationship('customer', 'name')
                        ->searchable()
                        ->preload()
                        ->native(false)
                        ->required(),
                ])
                ->columnSpanFull(),

            Grid::make(3)
                ->schema([
                    TextInput::make('quantity')
                        ->label('Jumlah Barang')
                        ->placeholder('0')
                        ->autocomplete(false)
                        ->required()
                        ->live()
                        ->afterStateUpdated(function ($state, callable $get, callable $set) use ($recalculateTotal, $recalculateRemaining): void {
                            $recalculateTotal($get, $set);
                            $recalculateRemaining($get, $set);
                        })
                        ->rules([
                            fn (callable $get, $record) => function (string $attribute, $value, $fail) use ($get, $record) {
                                $warehouseId = $get('warehouse_id');
                                $unitId = $get('unit_id');
                                $quantity = (float) str_replace(',', '.', $value);

                                if (! $warehouseId || ! $unitId || $quantity <= 0) {
                                    return;
                                }

                                $available = WarehouseStock::getQuantity($warehouseId, $unitId);

                                // If we are editing, we add back the current quantity
                                if ($record && $record->warehouse_id == $warehouseId && $record->unit_id == $unitId) {
                                    $available += (float) $record->quantity;
                                }

                                if ($available < $quantity) {
                                    $unitAlias = Unit::find($unitId)?->alias ?? 'satuan';
                                    $fail('Stok tidak mencukupi untuk unit ini di gudang tersebut. Tersedia: '.str_replace('.', ',', (float) $available)." {$unitAlias}");
                                }
                            },
                        ])
                        ->currencyMask(thousandSeparator: '.', decimalSeparator: ',', precision: 2)
                        ->formatStateUsing(fn ($state) => $state === null ? null : (float) $state)
                        ->dehydrateStateUsing($unmaskQty),

                    TextInput::make('unit_price')
                        ->label('Harga per Satuan')
                        ->placeholder('0')
                        ->autocomplete(false)
                        ->prefix('Rp')
                        ->required()
                        ->live()
                        ->currencyMask(thousandSeparator: '.', decimalSeparator: ',', precision: 0)
                        ->dehydrateStateUsing($unmaskMoney)
                        ->afterStateUpdated(function ($state, callable $get, callable $set) use ($recalculateTotal, $recalculateRemaining): void {
                            $recalculateTotal($get, $set);
                            $recalculateRemaining($get, $set);
                        }),

                    Select::make('unit_id')
                        ->label('Satuan')
                        ->relationship('unit', 'alias')
                        ->searchable()
                        ->preload()
                        ->native(false)
                        ->required()
                        ->live(),
                ]),

            Grid::make(3)
                ->schema([
                    TextInput::make('total_amount')
                        ->label('Total')
                        ->placeholder('0')
                        ->readOnly()
                        ->prefix('Rp')
                        ->required()
                        ->live()
                        ->formatStateUsing(
                            fn ($state) => number_format((float) ($state ?? 0), 0, ',', '.')
                        )
                        ->dehydrateStateUsing($unmaskMoney),

                    TextInput::make('paid_amount')
                        ->label('Jumlah yang Sudah Dibayar (DP)')
                        ->placeholder('0')
                        ->default(0)
                        ->autocomplete(false)
                        ->required()
                        ->live()
                        ->prefix('Rp')
                        ->readOnly(fn (callable $get) => $get('is_paid'))
                        ->afterStateUpdated(function ($state, callable $get, callable $set) use ($recalculateRemaining, $unmaskMoney): void {
                            $paidAmount = $unmaskMoney($state);
                            $totalAmount = $unmaskMoney($get('total_amount'));

                            $recalculateRemaining($get, $set);

                            if (! $get('is_paid')) {
                                $set('is_paid', $paidAmount >= $totalAmount && $totalAmount > 0);
                            }

                            if ($paidAmount >= $totalAmount && $totalAmount > 0 && ! $get('payment_date')) {
                                $set('payment_date', now());
                            }

                            if ($paidAmount < $totalAmount) {
                                $set('payment_date', null);
                            }
                        })
                        ->currencyMask(thousandSeparator: '.', decimalSeparator: ',', precision: 0)
                        ->dehydrateStateUsing($unmaskMoney),

                    TextInput::make('remaining_amount')
                        ->label('Sisa Pembayaran')
                        ->placeholder('0')
                        ->readOnly()
                        ->prefix('Rp')
                        ->default(0)
                        ->live()
                        ->formatStateUsing(function ($state, callable $get) use ($unmaskMoney) {
                            $paidAmount = $unmaskMoney($get('paid_amount'));
                            $totalAmount = $unmaskMoney($get('total_amount'));
                            $remaining = max(0, $totalAmount - $paidAmount);

                            return number_format($remaining, 0, ',', '.');
                        })
                        ->dehydrated(false),

                    Toggle::make('is_paid')
                        ->label('Lunas')
                        ->default(false)
                        ->live()
                        ->afterStateUpdated(function ($state, callable $get, callable $set) use ($recalculateRemaining, $unmaskMoney): void {
                            $totalAmount = $unmaskMoney($get('total_amount'));

                            if ($state) {
                                $set('paid_amount', number_format($totalAmount, 0, ',', '.'));

                                if (! $get('payment_date')) {
                                    $set('payment_date', now());
                                }
                            } else {
                                $set('paid_amount', 0);
                                $set('payment_date', null);
                            }

                            $recalculateRemaining($get, $set);
                        }),

                    DatePicker::make('payment_date')
                        ->label('Tanggal Pembayaran Lunas')
                        ->native(false)
                        ->displayFormat('l, d F Y')
                        ->visible(function (callable $get) use ($unmaskMoney) {
                            $paidAmount = $unmaskMoney($get('paid_amount'));
                            $totalAmount = $unmaskMoney($get('total_amount'));

                            return $paidAmount >= $totalAmount && $totalAmount > 0;
                        }),
                ]),

            Textarea::make('notes')
                ->label('Catatan')
                ->placeholder('...')
                ->autocomplete(false)
                ->columnSpanFull(),
        ])
            ->columns(1);
    }
}
