<?php

namespace App\Services\Navision;

use App\Helpers\StringHelper;
use App\Models\Order;
use App\Models\Product;
use App\Support\NavClient;
use Illuminate\Support\Facades\Log;
use RuntimeException;
use stdClass;

/**
 * Navision API service class
 */
class OrdersService {
    const NAV_SALES_DOCUMENT_TYPE_ORDER = 'Order';
    const NAV_SALES_DOCUMENT_TYPE_QUOTE = 'Quote';
    const NAV_ITEM_TYPE_ITEM = 'Item';
    const NAV_ITEM_TYPE_CHARGE_ITEM = 'Charge_Item';
    const NAV_ITEM_TYPE_DISCOUNT = 'CUST-CHRG';
    const NAV_ITEM_TYPE_RESOURCE = 'Resource';
    const NAV_ITEM_TYPE_TEXT = '_blank_';

    protected $client;

    public function __construct()
    {
        $this->client = new NavClient();
    }

    /**
     * Creates order in navision
     *
     * @param Order $order
     * @return void
     */
    public function createNavOrder(Order $order)
    {
        Log::info('Sending Order to NAV ID: ' . $order->id);

        if ($order->nav_no) {
            throw new RuntimeException('Navision create order failed: Order already sent to Navision');
        }

        $company = $order->company;
        $customer = $order->customer;
        $customerName = $customer->first_name . ' ' . $customer->last_name;

        $navOrder = new stdClass();

        $navOrder->Sell_to_Customer_No = $company->nav_no;
        // Not sending sell to customer anymore
        // $navOrder->Sell_to_Customer_Name = $company->name;
        $navOrder->Sell_to_Contact_No = $customer->nav_no;
        $navOrder->Sell_to_Contact = $customerName;

        $navOrder->Document_Type = self::NAV_SALES_DOCUMENT_TYPE_QUOTE;
        $navOrder->Quote_Date = $order->order_created_at->format('Y-m-d');
        $navOrder->Order_Date = $order->order_created_at->format('Y-m-d');
        $navOrder->External_Document_No = $order->number;
        $navOrder->Currency_Code = $order->currency;
        $navOrder->Total_amount_of_Order = $order->total;
        $navOrder->Email_Registered_User = $customer->email;
        $navOrder->Phone_Registered_User = $customer->phone;
        $navOrder->Registered_User = $customerName;
        $navOrder->Email_for_Invoice = $order->email;
        $navOrder->Shipping_Option = 'Incl_Shipping';
        $navOrder->Promised_Delivery = 'Webshop_Order';
        $navOrder->Payment_Option = 'Webshop_Payment';
        $navOrder->Invoice_Option = 'By_Email';
        $navOrder->Quote_Status = 'Placed';
        $navOrder->Quote_Type = 'Webshop';
        $navOrder->Description_of_Solution = "Webshop Order $order->number";
        $navOrder->Shortcut_Dimension_3_Code = 'OTHER';
        $navOrder->Shortcut_Dimension_4_Code = 'WEBSHOP';
        $navOrder->Shortcut_Dimension_6_Code = 'OTHER';
        $navOrder->Shortcut_Dimension_7_Code = 'EXISTING';
        $navOrder->Salesperson_Code = 'WEBSHOP';
        $navOrder->Your_Reference = $order->external_reference;

        if ($order->financial_status == 'paid') {
            $navOrder->Payment_Terms_Code = 'CC';
        } else {
            $navOrder->Payment_Terms_Code = '30D';
        }

        $navOrder->Sell_to_Address = StringHelper::cutToNav($order->billing_address1, 50, true);
        $navOrder->Sell_to_Address_2 = StringHelper::cutToNav($order->billing_address2, 50, true);
        $navOrder->Sell_to_Post_Code = StringHelper::cutToNav($order->billing_zip, 10, true);
        $navOrder->Sell_to_City =  StringHelper::cutToNav($order->billing_city, 30, true);

        $navOrder->Ship_to_Contact = StringHelper::cutToNav($order->shipping_name, 50, true);
        $navOrder->Ship_to_Name = StringHelper::cutToNav($order->shipping_company, 50, true);
        $navOrder->Ship_to_Name_2 = ' ';
        $navOrder->Ship_to_Address = StringHelper::cutToNav($order->shipping_address1, 50, true);
        $navOrder->Ship_to_Address_2 = StringHelper::cutToNav($order->shipping_address2, 50, true);
        $navOrder->Ship_to_Post_Code = StringHelper::cutToNav($order->shipping_zip, 10, true);
        $navOrder->Ship_to_City = StringHelper::cutToNav($order->shipping_city, 30, true);

        // Since NAV needs the ship to country code to be fulfilled even if the product is not physical, we fallback to the billing country
        $shippingCountryCode = $order->shipping_country_code ? $order->shipping_country_code : $order->billing_country_code;
        $navOrder->Ship_to_Country_Region_Code = StringHelper::cutToNav($shippingCountryCode, 10, true);
        $navOrder->Ship_to_County = StringHelper::cutToNav($order->shipping_province_code, 10, true);
        $navOrder->Ship_to_Email = $order->email;
        $navOrder->Ship_to_Phone_Number = StringHelper::cutToNav($order->shipping_phone, 30, true);

        $navOrder->Bill_to_Customer_No = $company->nav_no;
        $navOrder->Bill_to_Name = StringHelper::cutToNav($order->billing_company, 50, true);
        $navOrder->Bill_to_Name_2 = ' ';
        $navOrder->Bill_to_Address = StringHelper::cutToNav($order->billing_address1, 50, true);
        $navOrder->Bill_to_Address_2 = StringHelper::cutToNav($order->billing_address2, 50, true);
        $navOrder->Bill_to_Post_Code = StringHelper::cutToNav($order->billing_zip, 10, true);
        $navOrder->Bill_to_City = StringHelper::cutToNav($order->billing_city, 30, true);
        $navOrder->Bill_to_County = StringHelper::cutToNav($order->billing_province_code, 10, true);
        $navOrder->Bill_to_Country_Region_Code = StringHelper::cutToNav($order->billing_country_code, 10, true);
        $navOrder->Bill_to_Contact = StringHelper::cutToNav($order->billing_name, 50, true);
        $navOrder->Remarks = StringHelper::cutToNav($order->note, 100);

        $isTaxExempt = 'false';
        if ($order->note_attributes) {
            array_filter($order->note_attributes, function ($attribute) use (&$isTaxExempt, $navOrder) {
                if ($attribute['name'] == 'tax_exempt' && $attribute['value'] == '1') {
                    $isTaxExempt = 'true';
                }
                if ($attribute['name'] == 'broker_name') {
                    $navOrder->Broker_Name = $attribute['value'];
                }
                if ($attribute['name'] == 'broker_account_number') {
                    $navOrder->Broker_Number = $attribute['value'];
                }
            });
        }
        $navOrder->Tax_Exempt = $isTaxExempt;

        $orderLines = [];
        foreach ($order->orderItems as $item) {
            $product = $item->product;
            $line = new stdClass();
            $line->Document_Type = self::NAV_SALES_DOCUMENT_TYPE_QUOTE;
            $line->Type = $product && $product->item_type == Product::ITEM_TYPE_RESOURCE ? self::NAV_ITEM_TYPE_RESOURCE : self::NAV_ITEM_TYPE_ITEM;
            $line->No = $item->nav_no;
            $line->Quantity = $item->quantity;

            $line->Line_Amount = $item->total;
            $line->Shortcut_Dimension_6_Code = $customer->market;
            $line->Shortcut_Dimension_4_Code = 'OTHER';
            $line->Shortcut_Dimension_7_Code = 'EXISTING';

            if ($item->licenseExtensionProduct) {
                // License extensions don't have product or variant in the integration system
                $line->Unit_Price = $item->total / $item->quantity;
                $line->License_No = $item->licenseExtensionProduct->license_number;
                $line->Description_2 = $item->licenseExtensionProduct->product;
                $line->Shortcut_Dimension_3_Code = $item->licenseExtensionProduct->nvar == 'OB' ? 'OBS' : $item->licenseExtensionProduct->nvar;
            } else {
                $line->Unit_Price = $item->variant->price;
                $line->Shortcut_Dimension_3_Code = 'OTHER';
            }

            $orderLines[] = $line;
        }

        // Shipping
        if ($order->shipping_total > 0) {
            $line = new stdClass();
            $line->Document_Type = self::NAV_SALES_DOCUMENT_TYPE_QUOTE;
            $line->Type = self::NAV_ITEM_TYPE_CHARGE_ITEM;
            $line->Description = 'Shipping - ' . $order->shipping_type;
            $line->Quantity = 1;
            $line->Unit_Price = $order->shipping_total;
            $line->Line_Amount = $order->shipping_total;
            $line->No = 'SHIP';

            $line->Shortcut_Dimension_3_Code = 'OTHER';
            $line->Shortcut_Dimension_6_Code = $customer->market;
            $line->Shortcut_Dimension_4_Code = 'OTHER';
            $line->Shortcut_Dimension_7_Code = 'EXISTING';

            $orderLines[] = $line;
        }

        // Discount
        if ($order->total_discount > 0) {
            $line = new stdClass();
            $line->Document_Type = self::NAV_SALES_DOCUMENT_TYPE_QUOTE;
            $line->Type = self::NAV_ITEM_TYPE_ITEM;
            $line->Description = 'Discount';
            $line->Quantity = 1;
            $line->Unit_Price = $order->total_discount * -1;
            $line->Line_Amount = $order->total_discount * -1;
            $line->No = 'CUST-CHRG';

            $line->Shortcut_Dimension_3_Code = 'OTHER';
            $line->Shortcut_Dimension_6_Code = $customer->market;
            $line->Shortcut_Dimension_4_Code = 'OTHER';
            $line->Shortcut_Dimension_7_Code = 'EXISTING';

            $orderLines[] = $line;
        }

        // Tax
        if ($order->total_tax > 0) {
            if (!empty($order->tax_info)) {
                foreach ($order->tax_info as $taxInfo) {
                    $line = new stdClass();
                    $line->Document_Type = self::NAV_SALES_DOCUMENT_TYPE_QUOTE;
                    $line->Type = self::NAV_ITEM_TYPE_TEXT;
                    $line->Description = $taxInfo['title'];
                    if (!empty($taxInfo['rate'])) {
                        $line->Description .= ' (' . $taxInfo['rate'] * 100 . '%)';
                    }

                    $orderLines[] = $line;
                }
            }

            $line = new stdClass();
            $line->Document_Type = self::NAV_SALES_DOCUMENT_TYPE_QUOTE;
            $line->Type = config('navision.nav_item_type_tax');
            $line->Description = 'Sales Tax Payable';
            $line->Quantity = 1;
            $line->Unit_Price = $order->total_tax;
            $line->Line_Amount = $order->total_tax;
            $line->No = config('navision.nav_tax_account_number');

            $line->Shortcut_Dimension_3_Code = 'OTHER';
            $line->Shortcut_Dimension_6_Code = $customer->market;
            $line->Shortcut_Dimension_4_Code = 'OTHER';
            $line->Shortcut_Dimension_7_Code = 'EXISTING';

            $orderLines[] = $line;
        }

        $navOrder->SalesLines = $orderLines;
        Log::info(json_encode($navOrder));
        $quote = $this->client->createSales($navOrder);

        $order->nav_no = $quote->No;
        $order->save();

        Log::info('Order Sent with success NAV NO: ' . $order->nav_no);
    }
}
