<?php

namespace App\Nova\Resources\Ecommerce\Product\Product\Concerns;

use App\Jobs\Ecommerce\Product\UpdateProductRelations;
use App\Nova\Forms\NovaForm;
use App\Nova\Resources\Ecommerce\Product\Product\Product as ProductResource;
use App\Repositories\Ecommerce\Channel\ChannelRepository;
use App\Repositories\Ecommerce\Collection\CollectionRepository;
use App\Repositories\Ecommerce\Product\Barcode\BarcodeRepository;
use App\Repositories\Ecommerce\Product\Brand\BrandRepository;
use App\Repositories\Ecommerce\Product\Category\CategoryRepository;
use App\Repositories\Ecommerce\Product\NovaProductRepository;
use Ebess\AdvancedNovaMediaLibrary\Fields\Images;
use Exception;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
use Laravel\Nova\Fields\Boolean;
use Laravel\Nova\Fields\Hidden;
use Laravel\Nova\Fields\ID;
use Laravel\Nova\Fields\Number;
use Laravel\Nova\Fields\Select;
use Laravel\Nova\Fields\Text;
use Laravel\Nova\Fields\Trix;
use Laravel\Nova\Http\Requests\NovaRequest;
use Nurmuhammet\DynamicFields\DynamicFields;
use Nurmuhammet\ProductInventory\ProductInventory;
use Outl1ne\MultiselectField\Multiselect;
use ShuvroRoy\NovaTabs\Tab;
use ShuvroRoy\NovaTabs\Tabs;

class ProductFieldsForUpdate
{
    /**
     * Get the fields displayed by the resource on detail page.
     */
    public static function make(ProductResource $resource, NovaRequest $request): array
    {
        return [
            ID::make(),

            Text::make(__('Name'), 'name')
                ->rules('required', 'string', 'max:255'),

            Trix::make(__('Description'), 'description')
                ->withFiles('public')
                ->rules('nullable', 'string'),

            Images::make(__('Image'), 'uploads')
                ->required()
                ->rules('required')
                ->showStatistics()
                ->setFileName(fn ($originalFilename, $extension, $model) => sprintf('%s.%s', Str::random(70), $extension)),

            Text::make(__('Price'), 'cost_amount')
                ->rules('required', 'numeric'),

            Text::make(__('Purchase price'), 'readonly_price_amount')
                ->readonly()
                ->dependsOn(['cost_amount', 'categories'], NovaProductRepository::priceAmountDependsOn()),

            Hidden::make('price_amount')
                ->fillUsing(function ($request, $model, $attribute, $requestAttribute) {
                    $model->{$attribute} = $request->input('readonly_price_amount');
                }),

            Text::make(__('Price without discount'), 'old_price_amount')
                ->rules('nullable', 'gt:readonly_price_amount'),

            Boolean::make(__('Active'), 'is_visible')
                ->canSeeWhen('isAdmin', $resource),

            Tabs::make('Main', [
                Tab::make(__('Product relations'), [
                    Select::make(__('Brand'), 'brand_id')
                        ->displayUsingLabels()
                        ->searchable()
                        ->options(BrandRepository::values())
                        ->rules('nullable'),

                    Select::make(__('Channel'), 'channel')
                        ->displayUsingLabels()
                        ->searchable()
                        ->options(ChannelRepository::values())
                        ->rules('required')
                        ->resolveUsing(fn ($value, $resource, $attribute) => $resource->owner()?->id)
                        ->fillUsing(NovaForm::fillEmpty())
                        ->canSeeWhen('isAdmin', $resource),

                    Multiselect::make(__('Category'), 'categories')
                        ->options(CategoryRepository::namesWithTaxes())
                        ->help(__('Biggest tax is chosen from categories'))
                        ->rules('required')
                        ->resolveUsing(fn ($value, $resource, $attribute) => $value->pluck('id'))
                        ->fillUsing(NovaForm::fillEmpty()),

                    Multiselect::make(__('Collection'), 'collections')
                        ->options(CollectionRepository::values())
                        ->rules('nullable')
                        ->resolveUsing(fn ($value, $resource, $attribute) => $value->pluck('id'))
                        ->fillUsing(NovaForm::fillEmpty()),
                ]),
                Tab::make(__('Inventory'), [
                    ProductInventory::make(__('Inventory'), 'inventories')
                        ->rules('required')
                        ->dependsOn('channel', NovaProductRepository::inventoryDependsOn('channel'))
                        ->fillUsing(NovaForm::fillEmpty()),

                    Text::make('SKU', 'sku')
                        ->rules('nullable', 'string', 'max:255'),

                    Boolean::make(__('Generate new barcode'), 'generate_new_barcode')
                        ->onlyOnForms()
                        ->fillUsing(NovaForm::fillEmpty()),

                    Text::make(__('Barcode'), 'barcode')
                        ->rules('nullable', 'string', 'max:255', 'unique:products,barcode,{{resourceId}}')
                        ->dependsOn(
                            attributes: 'generate_new_barcode',
                            mixin: function ($field, $request, $formData) use ($resource) {
                                if (boolval($formData->generate_new_barcode)) {
                                    $field->setValue(BarcodeRepository::generateBarcode());

                                    return;
                                }

                                $field->setValue($resource->barcode);
                            }
                        ),

                    Number::make(__('Security stock'), 'security_stock')
                        ->rules('nullable', 'integer'),

                    Hidden::make('stock')
                        ->fillUsing(function ($request, $model, $attribute, $requestAttribute) {
                            $model->{$attribute} = array_sum(array_values($request->input('inventories')));
                        }),
                ]),
                Tab::make(__('Attributes'), [
                    DynamicFields::make('Attributes', 'workingpn')
                        ->fillWithArrayName('properties')
                        ->dependsOn(['categories'], NovaProductRepository::updateRequestAttributesDependsOn($resource))
                        ->fillUsing(function ($request, $model, $attribute, $requestAttribute) {
                            $properties = $request->input('properties');

                            if (! $properties) {
                                return;
                            }

                            foreach ($properties as $key => $value) {
                                try {
                                    if (in_array($key, ['size', 'colour'])) {
                                        $model->{$key} = $value;
                                    }
                                } catch (Exception) {
                                }
                            }
                        }),
                ]),
                Tab::make(__('Shipping'), [
                    Boolean::make(__('Back order'), 'back_order')
                        ->fillUsing(NovaForm::fillSchemalessField()),

                    Number::make(__('Weight value'), 'weight_value')
                        ->fillUsing(NovaForm::fillSchemalessField()),

                    Select::make(__('Weight unit'), 'weight_unit')
                        ->options(['kg' => 'kg'])
                        ->default('kg')
                        ->searchable()
                        ->fillUsing(NovaForm::fillSchemalessField()),

                    Number::make(__('Height value'), 'height_value')
                        ->fillUsing(NovaForm::fillSchemalessField()),

                    Select::make(__('Height unit'), 'height_unit')
                        ->options(['cm' => 'cm'])
                        ->default('cm')
                        ->searchable()
                        ->fillUsing(NovaForm::fillSchemalessField()),

                    Number::make(__('Width value'), 'width_value')
                        ->fillUsing(NovaForm::fillSchemalessField()),

                    Select::make(__('Width unit'), 'width_unit')
                        ->options(['cm' => 'cm'])
                        ->default('cm')
                        ->searchable()
                        ->fillUsing(NovaForm::fillSchemalessField()),

                    Number::make(__('Depth value'), 'depth_value')
                        ->fillUsing(NovaForm::fillSchemalessField()),

                    Select::make(__('Depth unit'), 'depth_unit')
                        ->options(['cm' => 'cm'])
                        ->default('cm')
                        ->searchable()
                        ->fillUsing(NovaForm::fillSchemalessField()),

                    Number::make(__('Volume value'), 'volume_value')
                        ->fillUsing(NovaForm::fillSchemalessField()),

                    Select::make(__('Volume unit'), 'volume_unit')
                        ->options(['kg' => 'kg'])
                        ->default('kg')
                        ->searchable()
                        ->fillUsing(NovaForm::fillSchemalessField()),
                ]),
                Tab::make(__('SEO'), [
                    Text::make(__('Seo title'), 'seo_title'),
                    Text::make(__('Seo description'), 'seo_description'),
                ]),
            ]),
        ];
    }

    /**
     * Register a callback to be called after the resource is updated.
     */
    public static function afterUpdate(NovaRequest $request, Model $model): void
    {
        UpdateProductRelations::dispatch(
            user: $request->user(),
            model: $model,
            categories: $request->input('categories'),
            collections: $request->input('collections'),
            channel: $request->input('channel'),
            properties: $request->input('properties'),
            inventories: $request->collect('inventories')
                ->mapWithKeys(fn ($stockValue, $inventoryID) => [$inventoryID => ['stock' => $stockValue]])
                ->toArray()
        );
    }
}
