<?php

namespace Hilco\Models;

use Exception;
use Illuminate\Database\Eloquent\Builder;
use Log;

/**
 * Hilco\Models\InventoryItem
 *
 * @property mixed $id
 * @property string $plant
 * @property mixed $plant_id
 * @property string $part_no
 * @property mixed $part_id
 * @property string $part_stat
 * @property string $part_src
 * @property string $part_type
 * @property boolean $part_taxable
 * @property boolean $kit_flag
 * @property boolean $on_bom
 * @property boolean $has_bom
 * @property integer $mfg_atp
 * @property string $date_created
 * @property string $date_modified
 * @property string $deleted_at
 * @property-read mixed $id_string
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\InventoryItem whereId($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\InventoryItem wherePlant($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\InventoryItem wherePlantId($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\InventoryItem wherePartNo($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\InventoryItem wherePartId($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\InventoryItem wherePartStat($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\InventoryItem wherePartSrc($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\InventoryItem wherePartType($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\InventoryItem wherePartTaxable($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\InventoryItem whereKitFlag($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\InventoryItem whereOnBom($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\InventoryItem whereHasBom($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\InventoryItem whereMfgAtp($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\InventoryItem whereFirstAvailQty($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\InventoryItem whereFirstAvailDt($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\InventoryItem whereMaxAvailQty($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\InventoryItem whereMaxAvailDt($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\InventoryItem whereDateCreated($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\InventoryItem whereDateModified($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\InventoryItem whereDeletedAt($value)
 * @mixin \Eloquent
 * @property integer $lot_control
 * @property string $date_uploaded
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\InventoryItem whereLotControl($value)
 * @method static \Illuminate\Database\Query\Builder|\Hilco\Models\InventoryItem whereDateUploaded($value)
 * @property string $vat_code
 * @property-read string $planning_policy_code
 * @property-read string $planning_policy_desc
 * @property-read string $planning_method_code
 * @property-read string $planning_method_desc
 */
class InventoryItem extends WebModel {
    protected $table = 'InventoryItems';

    const STATUS_DONOTREORDER   = 'DoNotReorder';
    const STATUS_OPEN           = 'Open';
    const STATUS_OBSOLETE       = 'Obsolete';

    const CUSTOM_PLANNING_POLICY_CODE = "Z4";
    const CUSTOM_PLANNING_METHOD_CODE = "3";

    /**
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     * @deprecated shouldn't be necessary anymore, use Part::partBOMs()
     */
    public function partBOMs() {
        return $this->hasMany(PartBOM::class, 'main_part_id', 'part_id');
    }

    public function part() {
        return $this->belongsTo(Part::class, 'part_id', 'id');
    }

    public function plantRelationship() {
        return $this->belongsTo(Plant::class, 'plant_id', 'id');
    }

    public function scopeInPlant(Builder $query, $plant) {
        return $query->where('plant', '=', $plant);
    }

    public function VATTax(){
        return  $this->belongsTo(VATTax::class, 'vat_code', 'vat_code')
            ->where('country', b2b()->activeCountry())
            ->where(function($query){
                $query->where(function($query){
                    return $query->where('effective_date','<=', date('Y-m-d',time()))
                        ->where('expiration_date','>=', date('Y-m-d',time()));
                })
                    ->orWhere('expiration_date', '0000-00-00');
            });
    }

    public function scopeAvailableInPlant(Builder $query, $activePlants = false) {
        if ($activePlants === false) $activePlants = b2b()->activePlants();
        $query->where(function ($query) use ($activePlants) {
            foreach ($activePlants as $activePlant) {
                if (!strlen($activePlant->plant)) continue;
                $query->orWhere(function ($query) use ($activePlant) {
                    return $query
                        ->where('plant', $activePlant->plant)
                        ->where('part_stat', '!=', InventoryItem::STATUS_OBSOLETE)
                        ->where(function ($query) {
                            $query
                                ->whereIn('web_flag', config('hilco.inventoryItemWebFlags'))
                                ->orWhereNull('web_flag')
                            ;
                        })
                    ;
                });
            }
            return $query;
        });
        return $query;
    }
    
    public function scopeAvailableInAnyPlant (Builder $query) {
        return
            $query
                ->where('part_stat', '!=', InventoryItem::STATUS_OBSOLETE)
                ->where(function ($query) {
                    $query
                        ->whereIn('web_flag', config('hilco.inventoryItemWebFlags'))
                        ->orWhereNull('web_flag')
                    ;
                })
        ;
    }

    public function scopeInSilo (Builder $query, $plants = false): Builder {
        if ($plants === false) $plants = b2b()->activePlants();
        $plantCodes = $plants->pluck('plant')->toArray();
        return $query
            ->whereIn('plant', $plantCodes)
            ->where('part_stat', '!=', InventoryItem::STATUS_OBSOLETE)
            ->where(function ($query) {
                return $query->whereNull('web_flag')->orWhereIn('web_flag', config('hilco.inventoryItemWebFlags'));
            });
    }

    public function scopeNotPhaseOut (Builder $query): Builder {
        return $query->where('part_stat', '!=', InventoryItem::STATUS_DONOTREORDER);
    }

    public function scopeIsValid(Builder $query) {
        $query->where('part_stat', '!=', InventoryItem::STATUS_OBSOLETE);
    }

    public function getIsValidAttribute() {
        return $this->part_stat != InventoryItem::STATUS_OBSOLETE;
    }

    public function getInStockAttribute() {
        // First check if the current active customer is default ship-from Las Vegas...
        $activeCustomer = b2b()->activeCustomer();
        $activeSegment = \Illuminate\Support\Arr::get($activeCustomer, 'activeSegment', false);
        if($activeSegment && $activeSegment->def_ship_from == Plant::LASVEGAS_CODE) {
            // ...because if so we need to only use the Las Vegas logic plants
            $activePlantNames = Plant::lasVegasLogicPlants();
        } else {
            // ...otherwise just use the current active plants
            $activePlantNames = b2b()->activePlants()->pluck('plant')->toArray();
        }

        // Don't bother considering this inventoryitem record if it isn't one of the active plants
        if (!(in_array($this->plant, $activePlantNames) && (is_null($this->web_flag) || in_array($this->web_flag, config('hilco.inventoryItemWebFlags'))))) {
            return false;
        }

        // Don't bother considering this inventoryitem record if the part is obsolete at this plant
        if ($this->part_stat == InventoryItem::STATUS_OBSOLETE) {
            return false;
        }

        // Now that we've made sure this inventoryitem record is one of the active plants and the part is not obsolete
        // check the ATP value for this part at this plant (the old check was "return net_avail > 0;", for reference)
        $atp = 0;
        try {
            $atpInfo = WebPart::fetchAllItemsStockInfo([$this->part_no], $this->plant);
            $atp = $atpInfo[$this->part_no]['stock'];
        }catch(Exception $e){
            Log::error("Exception caught while fetching stock info: " . $e->getMessage());
            return null;
        }

        return $atp > 0;
    }

    /**
     * @return string|null
     */
    public function getPlanningPolicyCode(): ?string {
        return $this->planning_policy_code;
    }

    /**
     * @return string|null
     */
    public function getPlanningMethodCode(): ?string {
        return $this->planning_method_code;
    }

    /**
     * @return bool
     */
    public function isCustomItem(): bool {
        return $this->getPlanningPolicyCode() == self::CUSTOM_PLANNING_POLICY_CODE && $this->getPlanningMethodCode() == self::CUSTOM_PLANNING_METHOD_CODE;
    }

    /**
     * @param $plant
     * @param $part
     * @return InventoryItem|null
     */
    public static function findFromPlantAndPart ($plant, $part): ?InventoryItem {
        $inventoryItem = self::where('plant_id', '=', $plant->id)->where('part_id', '=', $part->id)->first();
        return $inventoryItem ?? null;
    }
}

