<?php

namespace Hilco\Models;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Throwable;

/**
 * Model Class StagedOrder
 * @property integer id
 * @property string reference_number
 * @property integer division_id
 * @property string order_date
 * @property string order_due_date
 * @property string order_status
 * @property integer soldto_customer_id
 * @property integer billto_customer_id
 * @property integer customershippingaddress_id
 * @property string customer_po
 * @property string order_instructions
 * @property integer salesordersource_id
 * @property integer paymentterm_id
 * @property string currency_code
 * @property integer salesrep_id
 * @property integer plant_id
 * @property string ship_via
 * @property integer shippingpolicytype_id
 * @property integer deliverymethod_id
 * @property integer delivery_priority
 * @property integer deliveryterm_id
 * @property string comment_all
 * @property string comment_external
 * @property string comment_internal
 * @property string comment_display
 * @property string comment_picklist
 * @property string comment_deliverynote
 * @property string comment_manufacturing
 * @property string comment_invoice
 * @property float part_amount
 * @property float order_discount
 * @property float freight_amount
 * @property float tax_amount
 * @property float ins_amount
 * @property float order_amount
 * @property string email
 * @property integer webuser_id
 * @property string order_origin
 * @property integer createdby_id
 * @property integer lastmodifiedby_id
 * @property integer approver_webuser_id
 * @property string date_approved
 * @property string silo_approval_notes
 * @property integer websilo_id
 * @property mixed salesorder_id
 * @property string last_error_message
 * @property string last_exception
 * @property Division division
 * @property SalesRep salesRep
 * @property Customer soldtoCustomer
 * @property Customer billtoCustomer
 * @property Plant orderShipPlant
 * @property CustomerShippingAddress customerShippingAddress
 * @property DeliveryMethod deliveryMethod
 * @property DeliveryTerm deliveryTerm
 * @property ShippingPolicyType shippingPolicyType
 * @property PaymentTerm paymentTerms
 * @property Collection|StagedOrderLine[] stagedOrderLines
 * @property-read Collection|StagedOrderLine[] promoDiscountedOrderLines
 * @property-read Collection|StagedOrderLine[] rewardsExcludedOrderLines
 * @property SalesOrderSource salesOrderSource
 * @property Collection|CenposAuthorization[] cenposAuthorizations
 * @property Collection|Promotion_StagedOrder[] promotionStagedOrders
 * @property Order salesOrder
 * @method static Builder unprocessed()
 */
class StagedOrder extends StagingModel {
    protected $table = "StagedOrders";
    protected $fillable = [
        'reference_number',
        'division_id',
        'order_date',
        'order_due_date',
        'order_status',
        'soldto_customer_id',
        'billto_customer_id',
        'customershippingaddress_id',
        'customer_po',
        'order_instructions',
        'salesordersource_id',
        'paymentterm_id',
        'currency_code',
        'salesrep_id',
        'plant_id',
        'ship_via',
        'shippingpolicytype_id',
        'deliverymethod_id',
        'delivery_priority',
        'deliveryterm_id',
        'comment_all',
        'comment_external',
        'comment_internal',
        'comment_display',
        'comment_picklist',
        'comment_deliverynote',
        'comment_manufacturing',
        'comment_invoice',
        'part_amount',
        'order_discount',
        'freight_amount',
        'tax_amount',
        'ins_amount',
        'order_amount',
        'email',
        'webuser_id',
        'order_origin',
        'createdby_id',
        'lastmodifiedby_id',
        'approver_webuser_id',
        'date_approved',
        'silo_approval_notes',
        'websilo_id',
        'salesorder_id',
        'last_error_message',
        'last_exception',
    ];
    const PENDING = "PENDING";
    const PENDING_APPROVAL = "PENDING_APPROVAL";
    const EXPORTING = "EXPORTING";
    const TRANSFERRED = "TRANSFERRED";
    const B2B_ORDER_ORIGIN = "B2B";
    const VISIONWEB_ORDER_ORIGIN = "VISIONWEB";

    protected static array $allowedCommentVisibilities = [
        "all",
        "deliverynote",
        "display",
        "external",
        "internal",
        "invoice",
        "manufacturing",
        "picklist",
    ];

    /**
     * @param Builder $query
     * @return Builder
     */
    public function scopeUnprocessed (Builder $query): Builder {
        return $query->whereNull("salesorder_id")
            ->whereIn('order_status', [self::EXPORTING,self::PENDING]);
    }

    public function getReferenceNumber(): string {
        return $this->reference_number;
    }

    public function getOrderDate(): string {
        return $this->order_date;
    }

    public function getDueDate(): string {
        return $this->order_due_date;
    }

    public function getCurrencyCode(): string {
        return $this->currency_code;
    }

    public function getSalesrepId(): int {
        return $this->salesrep_id;
    }

    public function getCustomerPO(): ?string {
        return $this->customer_po;
    }

    public function getOrderInstructions(): ?string {
        return $this->order_instructions;
    }

    public function getDeliveryPriority(): int {
        return $this->delivery_priority;
    }

    public function getFreightAmount(): ?float {
        return $this->freight_amount;
    }

    public function getInsuranceAmount(): ?float {
        return $this->ins_amount;
    }

    public function getPartAmount(): ?float {
        return $this->part_amount;
    }

    public function getOrderStatusRaw(): string {
        return $this->order_status;
    }

    public function getOrderAmount(): ?float {
        return $this->order_amount;
    }

    public function getOrderDiscount(): ?float {
        return $this->order_discount;
    }

    public function getShippingNo(): string {
        return $this->customerShippingAddress->getAddrNo();
    }

    public function getShippingLine1(): string {
        return $this->customerShippingAddress->getAddressLine1();
    }

    public function getShippingLine2(): string {
        return $this->customerShippingAddress->getAddressLine2();
    }

    public function getShippingLine3(): string {
        return $this->customerShippingAddress->getAddressLine3();
    }

    public function getShippingCity(): string {
        return $this->customerShippingAddress->getCity();
    }

    public function getShippingState(): string {
        return $this->customerShippingAddress->getState();
    }

    public function getShippingZip(): string {
        return $this->customerShippingAddress->getPostalCode();
    }

    public function getShippingCountry(): string {
        return $this->customerShippingAddress->getCountryCode();
    }

    public function getShippingAttnOfName(): ?string {
        return $this->customerShippingAddress->getAttnOfName();
    }

    public function getShipVia(): ?string {
        return $this->ship_via;
    }

    public function getTaxAmount(): ?float {
        return $this->tax_amount;
    }

    public function getComment ($visibility): ?string {
        if (in_array($visibility, self::$allowedCommentVisibilities)) {
            $commentColumn = "comment_".$visibility;
            return $this->$commentColumn;
        }
        return null;
    }

    public function getOrigin(): string {
        return $this->order_origin;
    }

    public function getSiloApprovalNotes() {
        return $this->silo_approval_notes;
    }

    /**
     * @param Throwable $throwable
     * @return void
     */
    public function recordLatestException (Throwable $throwable) {
        $this->update([
            'last_error_message' => $throwable->getMessage(),
            'last_exception' => $throwable->getTraceAsString(),
        ]);
    }

    /**
     * @return BelongsTo
     */
    public function salesOrder(): BelongsTo {
        return $this->belongsTo(Order::class, "salesorder_id", "id");
    }

    /**
     * @return HasMany
     */
    public function stagedOrderLines(): HasMany {
        return $this->hasMany(StagedOrderLine::class, "stagedorder_id", "id");
    }

    public function getAppliedPromotions(): \Illuminate\Support\Collection {
        return Promotion::whereIn('id', $this->promotionStagedOrders->where('applied', '=', 1)->pluck('promotion_id')->toArray())->get();
    }

    /**
     * @return HasMany
     */
    public function cenposAuthorizations(): HasMany {
        return $this->hasMany(CenposAuthorization::class, "stagedorder_id", "id");
    }

    public function shippingPolicyType(): BelongsTo {
        return $this->belongsTo(ShippingPolicyType::class, "shippingpolicytype_id", "id");
    }

    public function customerShippingAddress(): BelongsTo {
        return $this->belongsTo(CustomerShippingAddress::class, 'customershippingaddress_id', 'id');
    }

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

    public function promotionStagedOrders(): HasMany {
        return $this->hasMany(Promotion_StagedOrder::class, "stagedorder_id", "id");
    }
}