<?php

namespace Webkul\Inventory\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\Auth;
use Spatie\EloquentSortable\Sortable;
use Spatie\EloquentSortable\SortableTrait;
use Webkul\Inventory\Database\Factories\RuleFactory;
use Webkul\Inventory\Enums\GroupPropagation;
use Webkul\Inventory\Enums\ProcureMethod;
use Webkul\Inventory\Enums\RuleAction;
use Webkul\Inventory\Enums\RuleAuto;
use Webkul\Partner\Models\Partner;
use Webkul\Security\Models\User;
use Webkul\Support\Models\Company;

class Rule extends Model implements Sortable
{
    use HasFactory, SoftDeletes, SortableTrait;

    protected $table = 'inventories_rules';

    protected $fillable = [
        'sort',
        'name',
        'route_sort',
        'delay',
        'group_propagation_option',
        'action',
        'procure_method',
        'auto',
        'push_domain',
        'location_dest_from_rule',
        'propagate_cancel',
        'propagate_carrier',
        'source_location_id',
        'destination_location_id',
        'route_id',
        'operation_type_id',
        'partner_address_id',
        'warehouse_id',
        'propagate_warehouse_id',
        'company_id',
        'creator_id',
        'procurement_group_id',
        'deleted_at',
    ];

    protected $casts = [
        'action'                   => RuleAction::class,
        'group_propagation_option' => GroupPropagation::class,
        'auto'                     => RuleAuto::class,
        'procure_method'           => ProcureMethod::class,
        'location_dest_from_rule'  => 'boolean',
        'propagate_cancel'         => 'boolean',
        'propagate_carrier'        => 'boolean',
    ];

    public $sortable = [
        'order_column_name'  => 'sort',
        'sort_when_creating' => true,
    ];

    public function sourceLocation(): BelongsTo
    {
        return $this->belongsTo(Location::class);
    }

    public function destinationLocation(): BelongsTo
    {
        return $this->belongsTo(Location::class);
    }

    public function route(): BelongsTo
    {
        return $this->belongsTo(Route::class);
    }

    public function operationType(): BelongsTo
    {
        return $this->belongsTo(OperationType::class);
    }

    public function warehouse(): BelongsTo
    {
        return $this->belongsTo(Warehouse::class);
    }

    public function propagateWarehouse(): BelongsTo
    {
        return $this->belongsTo(Warehouse::class);
    }

    public function partnerAddress(): BelongsTo
    {
        return $this->belongsTo(Partner::class);
    }

    public function procurementGroup(): BelongsTo
    {
        return $this->belongsTo(ProcurementGroup::class, 'procurement_group_id');
    }

    public function company(): BelongsTo
    {
        return $this->belongsTo(Company::class);
    }

    public function creator(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }

    public function getLeadDays($product, array $values = []): array
    {
        $delays = ['total_delay' => 0.0];

        $delay = $this->filter(function ($rule) {
            return in_array($rule->action, [RuleAction::PULL, RuleAction::PULL_PUSH], true);
        })->sum('delay');

        $delays['total_delay'] += $delay;

        $globalVisibilityDays = (int) ($this->context['global_visibility_days'] ?? 0);

        if ($globalVisibilityDays) {
            $delays['total_delay'] += $globalVisibilityDays;
        }

        if (! empty($this->context['bypass_delay_description'])) {
            $delayDescription = [];
        } else {
            $delayDescription = [];

            foreach ($this as $rule) {
                if (
                    in_array($rule->action, [RuleAction::PULL, RuleAction::PULL_PUSH], true)
                    && $rule->delay
                ) {
                    $delayDescription[] = [
                        __('inventories::system.rule.delay-on', ['name' => $rule->name]),
                        __('inventories::system.rule.days', ['days' => $rule->delay]),
                    ];
                }
            }
        }

        if ($globalVisibilityDays) {
            $delayDescription[] = [
                __('inventories::system.rule.time-horizon'),
                __('inventories::system.rule.days', ['days' => $globalVisibilityDays]),
            ];
        }

        return [$delays, $delayDescription];
    }

    protected static function newFactory(): RuleFactory
    {
        return RuleFactory::new();
    }

    protected static function boot()
    {
        parent::boot();

        static::creating(function ($rule) {
            $authUser = Auth::user();

            $rule->creator_id ??= $authUser->id;

            $rule->company_id ??= $authUser?->default_company_id;

            $rule->warehouse_id ??= $rule->operationType?->warehouse_id;

            $rule->group_propagation_option ??= GroupPropagation::PROPAGATE;
        });
    }
}
