<?php

namespace Hilco\Models;

use Carbon\Carbon;
use Hilco\SoftDeletes;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Query\Builder;
use Illuminate\Support\Facades\DB;
use Throwable;

/**
 * Hilco\Models\Order
 *
 * @property mixed $id
 * @property mixed $division_id
 * @property mixed $plant_id
 * @property string $invoice_number
 * @property string $web_order_number
 * @property mixed $billto_customersegment_id
 * @property mixed $soldto_customersegment_id
 * @property string $fob
 * @property string $payment_terms
 * @property float $tax_amt
 * @property float $freight_amt
 * @property string $invoice_date
 * @property string $ship_date
 * @property Carrier $carrier
 * @property string $ship_via
 * @property string $customer_po
 * @property string $order_type
 * @property string $shipping_policy
 * @property string $date_created
 * @property string $date_modified
 * @property string $deleted_at
 * @property-read mixed $affiliateSales
 * @property-read mixed $id_string
 * @method static Builder|Order whereId($value)
 * @method static Builder|Order whereDivisionId($value)
 * @method static Builder|Order wherePlantId($value)
 * @method static Builder|Order whereInvoiceNumber($value)
 * @method static Builder|Order whereWebOrderNumber($value)
 * @method static Builder|Order whereBilltoCustomersegmentId($value)
 * @method static Builder|Order whereSoldtoCustomersegmentId($value)
 * @method static Builder|Order whereFob($value)
 * @method static Builder|Order wherePaymentTerms($value)
 * @method static Builder|Order whereTaxAmt($value)
 * @method static Builder|Order whereFreightAmt($value)
 * @method static Builder|Order whereInvoiceDate($value)
 * @method static Builder|Order whereShipDate($value)
 * @method static Builder|Order whereCarrier($value)
 * @method static Builder|Order whereShipVia($value)
 * @method static Builder|Order whereCustomerPo($value)
 * @method static Builder|Order whereOrderType($value)
 * @method static Builder|Order whereShippingPolicy($value)
 * @method static Builder|Order whereDateCreated($value)
 * @method static Builder|Order whereDateModified($value)
 * @method static Builder|Order whereDeletedAt($value)
 * @mixin \Eloquent
 * @property string $hilco_order_number
 * @property string $order_date
 * @property string $order_due_date
 * @property string $order_status
 * @property string $ship_policy
 * @property integer $salesordertype_id
 * @property integer $salesordersource_id
 * @property string $ship_to_attention
 * @property integer $fob_id
 * @property integer $carrier_id
 * @property integer $paymentterm_id
 * @property string $order_instructions
 * @property string $currency_code
 * @property integer $salesrep_id
 * @property integer $billto_customer_id
 * @property integer $soldto_customer_id
 * @property string $shipping_line1
 * @property string $shipping_line2
 * @property string $shipping_line3
 * @property string $shipping_city
 * @property string $shipping_state
 * @property string $shipping_zip
 * @property string $shipping_country
 * @property string $comment_all
 * @property string $comment_external
 * @property string $comment_internal
 * @property string $comment_display
 * @property float $part_amount
 * @property float $misc_amount
 * @property float $part_discount
 * @property float $order_discount
 * @property float $freight_amount
 * @property float $tax_amount
 * @property float $ins_amount
 * @property float $order_amount
 * @property string $order_source
 * @property string $order_origin
 * @property integer $reward_tier
 * @property string $promo_code
 * @property string $state_license
 * @property string $plant
 * @property string $warehouse
 * @property string $bin_location
 * @property string $date_uploaded
 * @property integer $warehouse_id
 * @property integer $binlocation_id
 * @property string $authorization_code
 * @property float $authorized_amount
 * @property string $auth_reference_num
 * @property integer $deliverymethod_id
 * @property integer $delivery_priority
 * @property integer $deliveryterm_id
 * @property integer $customershippingaddress_id
 * @property string $shipping_no
 * @property string $email
 * @property integer $webuser_id
 * @property float $header_discount_amount
 * @property float $header_discount_percent
 * @property string $header_discount_desc
 * @property string $header_discount_code
 * @property float $handling_amount
 * @property string $shipping_attnofname
 * @property integer $shippingpolicytype_id
 * @property integer $commit_sequence
 * @method static Builder|Order whereHilcoOrderNumber($value)
 * @method static Builder|Order whereOrderDate($value)
 * @method static Builder|Order whereOrderDueDate($value)
 * @method static Builder|Order whereOrderStatus($value)
 * @method static Builder|Order whereShipPolicy($value)
 * @method static Builder|Order whereSalesordertypeId($value)
 * @method static Builder|Order whereSalesordersourceId($value)
 * @method static Builder|Order whereShipToAttention($value)
 * @method static Builder|Order whereFobId($value)
 * @method static Builder|Order whereCarrierId($value)
 * @method static Builder|Order wherePaymenttermId($value)
 * @method static Builder|Order whereOrderInstructions($value)
 * @method static Builder|Order whereCurrencyCode($value)
 * @method static Builder|Order whereSalesrepId($value)
 * @method static Builder|Order whereBilltoCustomerId($value)
 * @method static Builder|Order whereSoldtoCustomerId($value)
 * @method static Builder|Order whereShippingLine1($value)
 * @method static Builder|Order whereShippingLine2($value)
 * @method static Builder|Order whereShippingLine3($value)
 * @method static Builder|Order whereShippingCity($value)
 * @method static Builder|Order whereShippingState($value)
 * @method static Builder|Order whereShippingZip($value)
 * @method static Builder|Order whereShippingCountry($value)
 * @method static Builder|Order whereCommentAll($value)
 * @method static Builder|Order whereCommentExternal($value)
 * @method static Builder|Order whereCommentInternal($value)
 * @method static Builder|Order whereCommentDisplay($value)
 * @method static Builder|Order wherePartAmount($value)
 * @method static Builder|Order whereMiscAmount($value)
 * @method static Builder|Order wherePartDiscount($value)
 * @method static Builder|Order whereOrderDiscount($value)
 * @method static Builder|Order whereFreightAmount($value)
 * @method static Builder|Order whereTaxAmount($value)
 * @method static Builder|Order whereInsAmount($value)
 * @method static Builder|Order whereOrderAmount($value)
 * @method static Builder|Order whereOrderSource($value)
 * @method static Builder|Order whereStateLicense($value)
 * @method static Builder|Order wherePlant($value)
 * @method static Builder|Order whereWarehouse($value)
 * @method static Builder|Order whereBinLocation($value)
 * @method static Builder|Order whereDateUploaded($value)
 * @method static Builder|Order whereWarehouseId($value)
 * @method static Builder|Order whereBinlocationId($value)
 * @method static Builder|Order whereAuthorizationCode($value)
 * @method static Builder|Order whereAuthorizationAmount($value)
 * @method static Builder|Order whereAuthReferenceNum($value)
 * @property-read Division $division
 * @property-read Collection|SalesOrderLine[] $partLines
 * @property-read Customer $soldToCustomer
 * @property-read Customer $billToCustomer
 * @property-read Plant $orderShipPlant
 * @property-read Customer $customer
 * @property-read SalesOrderSource $salesOrderSource
 */
class Order extends UuidModel
{
	protected $table = 'SalesOrders';
    protected $fillable = [
        'id',
        'division_id', 'web_order_number', 'hilco_order_number',
        'order_date', 'order_due_date', 'order_status',
        'ship_policy', 'shippingpolicytype_id', 'ship_via',
        'paymentterm_id', 'customer_po', 'order_instructions', 'currency_code', 'salesrep_id',
        'billto_customer_id', 'soldto_customer_id', 'customershippingaddress_id',
        'shipping_no', 'shipping_line1', 'shipping_line2', 'shipping_line3',
        'shipping_city', 'shipping_state', 'shipping_zip', 'shipping_country',
        'order_source', 'plant', 'plant_id', 'order_origin',
        'deliverymethod_id', 'deliveryterm_id', 'delivery_priority',
        'salesordersource_id', 'shipping_attnofname',
        'part_amount', 'misc_amount', 'freight_amount', 'part_discount',
        'order_discount', 'tax_amount', 'handling_amount', 'ins_amount', 'order_amount',
        'comment_all', 'comment_deliverynote', 'comment_display', 'comment_external',
        'comment_internal', 'comment_invoice', 'comment_manufacturing', 'comment_picklist',
        'commit_sequence',
    ];

	public static array $categories = [
		'overallsales' => '',
		'rxsales' => ['RX SAFETY'],
		'lenscaresales' => ['LC / BRANDING OTHER'],
		'consumersales' => ['ACCESSORIES OTHER'],
		'brandingsales' => ['LC / BRANDING OTHER'],
		'examinationsales' => ['EXAM SUPPLIES'],
		'customizationsales' => ['REPAIR PARTS OTHER'],
		'lowvisionsales' => ['RX SAFETY'],
		'dispensingsales' => ['LIQUID']

	];

	// Order Status Values
	const PENDING_STATUS            = 'PENDING'; // standard status, order is "pending" export to M3
	const PENDING_WEB_STATUS        = 'PENDING_WEB'; // status signifying order needs microsite approval
    const DENIED_STATUS             = 'DENIED'; // status signifying the microsite approver rejected the order
	const PENDING_APPROVAL_STATUS   = 'PENDING_APPROVAL'; // status signifying order needs approval by a CSR in CST

	const B2B_ORDER_ORIGIN          = 'B2B';
	const CST_ORDER_ORIGIN          = 'CST';
    const CST_WEB_ORDER_ORIGIN      = 'CSTWEB';
	const LEGACY_ORDER_ORIGIN       = 'HISTORY';
	const M3_ORDER_ORIGIN           = 'M3';
    const VISIONWEB_ORDER_ORIGIN    = 'VISIONWEB';

    use SoftDeletes;

    /**
     * @param StagedOrder $stagedOrder
     * @param int $commit_sequence
     * @return Order
     * @throws Throwable
     */
    public static function createFromStaged (StagedOrder $stagedOrder, int $commit_sequence): Order {
        $salesOrder = new Order([
            'id' => generateUUID(),
            'division_id' => $stagedOrder->division_id,
            'web_order_number' => $stagedOrder->getReferenceNumber(),
            'hilco_order_number' => $stagedOrder->getReferenceNumber(),
            'order_date' => $stagedOrder->getOrderDate(),
            'order_due_date' => $stagedOrder->getDueDate(),
            'order_status' => Order::PENDING_STATUS,
            'ship_policy' => $stagedOrder->shippingPolicyType->getCode(),
            'shippingpolicytype_id' => $stagedOrder->shippingpolicytype_id,
            'ship_via' => $stagedOrder->getShipVia(),
            'paymentterm_id' => $stagedOrder->paymentterm_id,
            'customer_po' => $stagedOrder->getCustomerPO(),
            'order_instructions' => $stagedOrder->getOrderInstructions(),
            'currency_code' => $stagedOrder->getCurrencyCode(),
            'salesrep_id' => $stagedOrder->salesrep_id,
            'billto_customer_id' => $stagedOrder->billto_customer_id,
            'soldto_customer_id' => $stagedOrder->soldto_customer_id,
            'customershippingaddress_id' => $stagedOrder->customershippingaddress_id,
            'shipping_no' => $stagedOrder->getShippingNo(),
            'shipping_line1' => $stagedOrder->getShippingLine1(),
            'shipping_line2' => $stagedOrder->getShippingLine2(),
            'shipping_line3' => $stagedOrder->getShippingLine3(),
            'shipping_city' => $stagedOrder->getShippingCity(),
            'shipping_state' => $stagedOrder->getShippingState(),
            'shipping_zip' => $stagedOrder->getShippingZip(),
            'shipping_country' => $stagedOrder->getShippingCountry(),
            'order_source' => Order::CST_WEB_ORDER_ORIGIN,
            'plant' => $stagedOrder->orderShipPlant->getWarehouseCode(),
            'plant_id' => $stagedOrder->plant_id,
            'order_origin' => Order::CST_WEB_ORDER_ORIGIN,
            'deliverymethod_id' => $stagedOrder->deliverymethod_id,
            'deliveryterm_id' => $stagedOrder->deliveryterm_id,
            'delivery_priority' => $stagedOrder->getDeliveryPriority(),
            'salesordersource_id' => $stagedOrder->salesordersource_id,
            'shipping_attnofname' => $stagedOrder->getShippingAttnOfName(),
            'part_amount' => $stagedOrder->getPartAmount(),
            'misc_amount' => 0,
            'freight_amount' => $stagedOrder->getFreightAmount(),
            'part_discount' => 0,
            'order_discount' => $stagedOrder->getOrderDiscount(),
            'tax_amount' => $stagedOrder->getTaxAmount(),
            'handling_amount' => 0,
            'ins_amount' => $stagedOrder->getInsuranceAmount(),
            'order_amount' => $stagedOrder->getOrderAmount(),
            'commit_sequence' => $commit_sequence,
            'comment_all' => $stagedOrder->getComment("all"),
            'comment_deliverynote' => $stagedOrder->getComment("deliverynote"),
            'comment_display' => $stagedOrder->getComment("display"),
            'comment_external' => $stagedOrder->getComment("external"),
            'comment_internal' => $stagedOrder->getComment("internal"),
            'comment_invoice' => $stagedOrder->getComment("invoice"),
            'comment_manufacturing' => $stagedOrder->getComment("manufacturing"),
            'comment_picklist' => $stagedOrder->getComment("picklist"),
        ]);
        $salesOrder->saveOrFail();
        return $salesOrder;
    }

    public function import_SalesOrder(){
        return $this->hasOne(Import_SalesOrder::class, 'salesorder_id');
    }
    
    public function authorization(){
        return $this->hasOne(CreditCardAuthorization::class, 'salesorder_id');
    }

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

	public function fob() {
		return $this->belongsTo(FOB::class, "fob_id");
	}

	public function salesrep() {
		return $this->belongsTo(SalesRep::class, "salesrep_id");
	}

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

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

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

	public function orderLineSchedules()
	{
		return $this->hasMany(SalesOrderLineSchedule::class, 'salesorder_id');
	}

	public function carrier() {
		return $this->belongsTo(Carrier::class, "carrier_id");
	}

	public function deliveryMethodTerm(){
	    return DeliveryMethodTerm::delivery($this->deliverymethod_id, $this->deliveryterm_id, $this->delivery_priority);
    }

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

    public function deliveryTerm(){
	    return $this->belongsTo(DeliveryTerm::class, "deliveryterm_id");
    }
	
	public function division() {
		return $this->belongsTo(Division::class, "division_id");
	}

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

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

//	public function mainLines()
//	{
//		return $this->hasMany(OrderMainLine::class, 'salesorder_id')
//			->join('SalesOrderPartLines', 'SalesOrderMainLines.parent_id', '=', 'SalesOrderPartLines.id')
//			->join('Parts', 'SalesOrderPartLines.part_id', '=', 'Parts.id')
//			->join('ProductFamily', 'Parts.productfamily_id', '=', 'ProductFamily.id')
//			->join('ProductCategories', 'ProductFamily.productcategory_id', '=', 'ProductCategories.id')
//			->join('ProductCategoryGroups', 'ProductCategories.productcategorygroup_id', '=', 'ProductCategoryGroups.id')
//			->where('SalesOrderMainLines.deleted_at', '=', "0")
////			->groupBy('ProductCategories.product_category')
////			->addSelect('SalesOrderMainLines.*', 'ProductCategories.product_category','ProductCategoryGroups.product_category_group')
////			->addSelect(DB::raw('SUM(SalesOrders.order_amount) as category_total'))
//			;
//	}

	public function partLines() {
	    return $this->hasMany(SalesOrderLine::class, 'salesorder_id')->where('deleted_at', '=', '0000-00-00')->with('part');
//		return $this->hasMany(OrderMainLine::class, 'salesorder_id')->where('parent_type', 'SalesOrderPartLines')->where('deleted_at', '=', '0000-00-00')->with('partLines.part');
	}

	public function miscLines() {
		return $this->hasMany(OrderMainLine::class, 'salesorder_id')->where('parent_type', 'SalesOrderMiscLines')->where('deleted_at', '=', '0000-00-00')->with('miscLines.miscCharge');
	}
	
	public function soldToCustomer() {
		return $this->belongsTo(Customer::class, "soldto_customer_id");
	}

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

	public function billToCustomerSegment() {
	    $activeSegments = $this->billToCustomer->activeSegments;
	    if ($activeSegments) {
	        return $activeSegments->take(1);
        } else {
	        return null;
        }
    }

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

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

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

	public function orderShipWarehouse() {
		return $this->belongsTo(Warehouse::class, 'warehouse_id');
	}

	public function orderShipBinLocation() {
		return $this->belongsTo(BinLocation::class, 'binlocation_id');
	}

	public function creditCardAuthorization() {
	    return $this->hasMany(CreditCardAuthorization::class, 'salesorder_id');
    }

    public function cstEnteredPharmacyInfo() {
	    return $this->hasOne(CSTEnteredPharmacyInfo::class, 'salesorder_id');
    }
	
	public function comments() {

		$comments = [];
		if ($this->comment_all != null && $this->comment_all != '') {
			$comments['A'] = $this->comment_all;
		}
		if ($this->comment_external != null && $this->comment_external != '') {
			$comments['E'] = $this->comment_external;
		}
		if ($this->comment_internal != null && $this->comment_internal != '') {
			$comments['I'] = $this->comment_internal;
		}
		if ($this->comment_display != null && $this->comment_display != '') {
			$comments['D'] = $this->comment_display;
		}

		return $comments;
	}

	public function orderParts()
	{
        $orderParts = $this->hasMany(SalesOrderLine::class, 'salesorder_id')
            ->join('Parts', 'SalesOrderLines.part_id', '=', 'Parts.id');

		return $orderParts;
	}

	public function scopeSubmitted($query) {
	    return $query->whereNotIn('order_status', ['UNSUBMITTED', 'DISCARDED', 'CANCELED', 'CANCELLED']);
    }

	public function scopeLastOrders($query, $soldToCustomerId, $take) {
	    return $query
            ->where('soldto_customer_id', $soldToCustomerId)
            ->orderBy('order_date', 'desc')
            ->with('orderParts')
            ->take($take);
    }

    public function scopeDateBetween($query, $fromDate, $toDate = false) {
        if ($toDate === false) {
            $query->where('order_date', '>=', $fromDate);
        } else {
            $query->whereBetween('order_date', [$fromDate, $toDate]);
        }
        return $query;
    }

    public function getFriendlyOrderStatusAttribute() {
        return $this->friendlyStatus($this->order_status);
    }

    public static function friendlyStatus($status) {
        switch ($status) {
            case 'CLOSED':
                return 'Closed';
            case 'PENDING_WEB':
                return 'Pending Approval';
            case 'DENIED':
                return 'Approval Denied';
        }

        return 'Open';
    }

    public function getTotalQuantityAttribute() {
        $qty = 0;
        $partLines = $this->partLines;
        if ($partLines) {
            foreach($partLines as $partLine){
                $qty += $partLine->quantity;
            }
        }

        return $qty;
    }

    public function getTotalShippedAttribute() {
        $qtyShipped = 0;
        if (isset($this->import_SalesOrder)) {
            foreach ($this->import_SalesOrder->shipmentUnitItems as $shipmentUnitItem) {
                $qtyShipped += $shipmentUnitItem->qty_shipped;
            }
        }
        return $qtyShipped;
    }

    public function getTrackingNumbersAttribute() {
        $numbers = [];
        foreach ($this->orderLineSchedules as $lineSchedule) {
            $numbers[$lineSchedule->shipment->tracking_number] = $lineSchedule->shipment->tracking_number;
        }
        return $numbers;
    }

    public function scopeToday($query) {
//        return $query->whereBetween('date_created', [Carbon::today()->startOfDay()->toDateTimeString(), Carbon::today()->endOfDay()->toDateTimeString()]);
        return $query->where('order_date', Carbon::today()->toDateString());
    }

    public function scopeWebOrders($query) {
        return $query->where('order_origin', 'B2B');
    }

    public function scopeCstOrders($query) {
        return $query->where('hilco_order_number', 'RLIKE', '^[HUW]')->where(function ($where) {
            $where->whereNull('order_origin')->orWhere('order_origin', '!=', 'B2B');
        });
    }

    public function getApprovedAttribute() {
	    return (bool) !($this->order_status == 'PENDING_WEB' || $this->order_status == 'DENIED');
    }

    public function promotions() {
	    return $this->belongsToMany(Promotion::class,
                                    'Promotion_SalesOrder',
                            'salesorder_id',
                            'promotion_id')
                    ->wherePivot('applied', '=', 1);
    }

    public function priceListSalesOrder() {
	    return $this->hasOne(PriceList_SalesOrder::class, 'salesorder_id');
    }

    public function approvalReasonSalesOrder() {
        return $this->hasOne(ApprovalReasonSalesOrder::class, 'salesorder_id', 'id');
    }
}