<?php

namespace App\Filament\Resources\InvoiceResource\Pages;

use App\Filament\Resources\InvoiceResource;
use App\Filament\Support\Perm;
use App\Filament\Support\ProductSelect;
use App\Filament\Support\RelationSelect;
use App\Models\Catalog\Product;
use App\Models\Sales\Invoice;
use App\Services\InvoiceService;
use App\Support\Quantity;
use Filament\Forms\Components\DatePicker;
use Filament\Forms\Components\Repeater;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Resources\Pages\CreateRecord;
use Filament\Schemas\Components\Section;
use Filament\Schemas\Components\Utilities\Get;
use Filament\Schemas\Schema;
use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\ValidationException;
use RuntimeException;

/**
 * Ported from InvoiceController::createLegacy()/storeLegacy() — recording a
 * pre-system invoice from the old paper books via InvoiceService::createLegacy().
 *
 * Source rules kept as-is:
 *  - invoice_number is the original paper number and must be unique.
 *  - invoice_date must be today or earlier; the invoice is backdated to it.
 *  - `total` is required only when no line items are supplied.
 *  - legacy line items must reference a real product (no free-text names), so
 *    returns and stock history still link to a real product.
 *  - settled_amount may not exceed the invoice value.
 *  - no stock movements are written — the goods left long before the system.
 */
class CreateLegacyInvoice extends CreateRecord
{
    protected static string $resource = InvoiceResource::class;

    protected static ?string $title = 'Add legacy invoice';

    public function form(Schema $schema): Schema
    {
        return $schema->components([
            Section::make()->schema([
                TextInput::make('invoice_number')
                    ->label('Original invoice #')
                    ->required()->maxLength(50)
                    ->unique('invoices', 'invoice_number'),
                RelationSelect::make(
                    name: 'customer_id',
                    relationship: 'customer',
                    titleAttribute: 'business_name',
                    modifyQueryUsing: fn ($query) => $query->where('is_active', true),
                    createPermission: 'isms_customers.create',
                )->label('Customer')->required(),
                RelationSelect::make(
                    name: 'branch_id',
                    relationship: 'branch',
                    titleAttribute: 'name',
                    modifyQueryUsing: fn ($query) => $query->where('is_active', true),
                )->label('Branch')->required(),
                DatePicker::make('invoice_date')
                    ->required()
                    ->maxDate(now())
                    ->helperText('The date on the paper invoice.'),
                TextInput::make('total')
                    ->numeric()->minValue(0.01)->maxValue(99999999.99)->prefix('Rs.')
                    ->helperText('Required when no line items are entered.'),
                TextInput::make('discount')
                    ->numeric()->minValue(0)->maxValue(99999999.99)->prefix('Rs.')->default(0)
                    ->visible(fn (): bool => Perm::can('isms_invoices', 'discount')),
                TextInput::make('settled_amount')
                    ->label('Already settled')
                    ->numeric()->minValue(0)->maxValue(99999999.99)->prefix('Rs.')->default(0),
                Textarea::make('note')->maxLength(500)->columnSpanFull(),
            ])->columns(3),

            Section::make('Items (optional)')->schema([
                Repeater::make('items')
                    ->schema([
                        ProductSelect::standalone(
                            modifyQueryUsing: fn ($query) => $query->where('is_active', true),
                        )->label('Product')->required()->live()->columnSpanFull(),
                        TextInput::make('quantity')
                            ->numeric()->required()->minValue(0.01)->maxValue(1000000)
                            ->suffix(fn (Get $get): ?string => Quantity::unitLabel(Product::find($get('product_id'))?->baseUnit)),
                        TextInput::make('unit_price')
                            ->numeric()->required()->minValue(0)->maxValue(99999999.99)->prefix('Rs.'),
                    ])
                    ->columns(2)
                    ->defaultItems(0)
                    ->addActionLabel('Add item')
                    ->columnSpanFull(),
            ]),
        ]);
    }

    protected function handleRecordCreation(array $data): Invoice
    {
        InvoiceResource::assertBranchAccessible((int) $data['branch_id']);

        // The field is hidden without the permission, but a crafted payload
        // could still submit one — rejected outright since there is no prior
        // record value to fall back on the way EditInvoice preserves one.
        if ((float) ($data['discount'] ?? 0) > 0 && ! Auth::user()?->hasPermissionTo('isms_invoices.discount')) {
            throw ValidationException::withMessages([
                'data.discount' => 'You do not have permission to apply a discount to an invoice.',
            ]);
        }

        $items = $data['items'] ?? [];

        if ($items === [] && ! ($data['total'] ?? null)) {
            throw ValidationException::withMessages([
                'data.total' => 'A total is required when no line items are entered.',
            ]);
        }

        // Resolve product names server-side from the selected product ids.
        $productNames = Product::whereIn('id', collect($items)->pluck('product_id')->filter())
            ->pluck('name', 'id');

        $lines = collect($items)
            ->map(fn (array $item): array => [
                'product_id' => (int) $item['product_id'],
                'product_name' => $productNames[$item['product_id']] ?? '',
                'quantity' => (float) $item['quantity'],
                'unit_price' => (float) $item['unit_price'],
            ])
            ->values()
            ->all();

        $subtotal = $lines === []
            ? (float) ($data['total'] ?? 0)
            : array_sum(array_map(fn (array $l): float => $l['quantity'] * $l['unit_price'], $lines));
        $netTotal = max(0, $subtotal - (float) ($data['discount'] ?? 0));
        $settled = round((float) ($data['settled_amount'] ?? 0), 2);

        if ($settled > $netTotal + 0.001) {
            throw ValidationException::withMessages([
                'data.settled_amount' => 'Already-settled amount cannot exceed the invoice value ('.number_format($netTotal, 2).').',
            ]);
        }

        try {
            return app(InvoiceService::class)->createLegacy(
                header: [
                    'invoice_number' => trim($data['invoice_number']),
                    'customer_id' => (int) $data['customer_id'],
                    'branch_id' => (int) $data['branch_id'],
                    'invoice_date' => $data['invoice_date'],
                    'total' => (float) ($data['total'] ?? 0),
                    'discount' => (float) ($data['discount'] ?? 0),
                    'note' => $data['note'] ?? null,
                ],
                lines: $lines,
                settledAmount: $settled,
            );
        } catch (RuntimeException $e) {
            throw ValidationException::withMessages(['data.total' => $e->getMessage()]);
        }
    }

    protected function getRedirectUrl(): string
    {
        return InvoiceResource::getUrl('view', ['record' => $this->record]);
    }
}
