<?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 CustomerShippingAddress shipToAddress
 * @property CustomerShippingAddress shipToAddressWithTrashed
 * @property DeliveryMethod deliveryMethod
 * @property DeliveryTerm deliveryTerm
 * @property ShippingPolicyType shippingPolicyType
 * @property PaymentTerm paymentTerms
 * @property Collection|StagedOrderLine[] stagedOrderLines
 * @property Collection|StagedOrderLine[] partLines
 * @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',
    ];
    const UNSUBMITTED = "UNSUBMITTED";
    const PENDING_APPROVAL = "PENDING_APPROVAL";
    const PENDING_WEB = "PENDING_WEB";
    const PENDING = "PENDING";
    const DENIED = "DENIED";
    const B2B_ORDER_ORIGIN = "B2B";

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

    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 getOrderStatus(): 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 isWebApproved(): bool {
        return $this->order_status !== self::PENDING_WEB && $this->order_status !== self::DENIED;
    }

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

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

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

    public function approvedByUser() {
        return $this->belongsTo(WebUser::class, 'approver_webuser_id', 'id');
    }

    public function billToCustomer(): BelongsTo {
        return $this->belongsTo(Customer::class, 'billto_customer_id', 'id');
    }

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

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

    public function deliveryMethod(): BelongsTo {
        return $this->belongsTo(DeliveryMethod::class, 'deliverymethod_id', 'id');
    }

    public function deliveryTerm(): BelongsTo {
        return $this->belongsTo(DeliveryTerm::class, 'deliveryterm_id', 'id');
    }

    public function division(): BelongsTo {
        return $this->belongsTo(Division::class, 'division_id', 'id');
    }

    public function orderedByUser() {
        return $this->belongsTo(WebUser::class, 'webuser_id', 'id');
    }

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

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

    public function paymentTerms(): BelongsTo {
        return $this->belongsTo(PaymentTerm::class, 'paymentterm_id', 'id');
    }

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

    public function salesOrderSource(): BelongsTo {
        return $this->belongsTo(SalesOrderSource::class, 'salesordersource_id', 'id');
    }

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

    public function salesRep(): BelongsTo {
        return $this->belongsTo(SalesRep::class, 'salesrep_id', 'id');
    }

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

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

    public function shipToAddressWithTrashed() {
        return $this->belongsTo(CustomerShippingAddress::class, "customershippingaddress_id", "id")->withTrashed();
    }

    public function soldToCustomer(): BelongsTo {
        return $this->belongsTo(Customer::class, 'soldto_customer_id', 'id');
    }

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

    public function webSilo(): BelongsTo {
        return $this->belongsTo(WebSilo::class, 'websilo_id', 'id');
    }

    public function webUser(): BelongsTo {
        return $this->belongsTo(WebUser::class, 'webuser_id', 'id');
    }

}