<?php

namespace App\Filament\Resources\ProductResource\Pages;

use App\Filament\Resources\ProductResource;
use App\Models\Catalog\Product;
use App\Services\AuditLog;
use App\Services\VatSettings;
use App\Support\ProductAttributeSync;
use Filament\Resources\Pages\EditRecord;

class EditProduct extends EditRecord
{
    protected static string $resource = ProductResource::class;

    /**
     * @var array<string, mixed>
     */
    protected array $originalValues = [];

    /**
     * @var array<int, array{key?: string, value?: string|null}>
     */
    protected array $pendingAttributes = [];

    /** The image this save orphaned, deleted only once the save has committed. */
    protected ?string $replacedImagePath = null;

    protected function mutateFormDataBeforeFill(array $data): array
    {
        $data['attributes'] = $this->record->attributes()
            ->orderBy('sort_order')
            ->get(['key', 'value'])
            ->map(fn ($a) => ['key' => $a->key, 'value' => $a->value])
            ->all();

        return $data;
    }

    protected function mutateFormDataBeforeSave(array $data): array
    {
        $this->originalValues = $this->record->only([
            'name', 'sku', 'main_category_id', 'sub_category_id', 'base_unit_id', 'is_active',
        ]);

        $this->pendingAttributes = array_values($data['attributes'] ?? []);
        unset($data['attributes']);

        /** @var Product $product */
        $product = $this->record;
        $previousImage = $product->image_url;

        $data = ProductResource::applyImageInput($data, $product);

        // Only once the save has actually committed does the old file become
        // unreferenced — deleting it here would lose the image on a save that
        // then fails validation downstream. Stashed for afterSave().
        $this->replacedImagePath = array_key_exists('image_url', $data) && $data['image_url'] !== $previousImage
            ? $previousImage
            : null;

        // The form field is hidden while VAT is off, but a hidden field can
        // still dehydrate a stale value — force it back to 0 server-side too.
        if (! app(VatSettings::class)->enabled()) {
            $data['vat_rate'] = 0;
        }

        // Expiry tracking only applies to batch-tracked products.
        if (empty($data['is_batch_tracked'])) {
            $data['is_expiry_tracked'] = false;
        }

        return $data;
    }

    protected function afterSave(): void
    {
        /** @var Product $product */
        $product = $this->record;

        ProductAttributeSync::apply($product, $this->pendingAttributes);

        ProductResource::deleteStoredImage($this->replacedImagePath);
        $this->replacedImagePath = null;

        $changes = [];
        foreach ($this->originalValues as $field => $old) {
            if ($old !== $product->{$field}) {
                $changes[$field] = ['from' => $old, 'to' => $product->{$field}];
            }
        }

        AuditLog::record('product.updated', $product, [
            'name' => $product->name,
            'code' => $product->sku,
            'changed' => array_keys($changes),
            'changes' => $changes,
        ]);
    }
}
