<?php

namespace Hilco\Taxes;

use ArrayAccess;
use GuzzleHttp\Client;
use Illuminate\Support\Arr;

class TaxHelper {
    /**
     * @param $part
     * @param $shippingAddress
     * @param $linePrice
     * @return array|mixed
     */
    public function getPartTaxability ($part, $shippingAddress, $linePrice) {
        $client = new Client([
            'base_uri' => config('m3-config.host').config('m3-config.environment').config('m3-config.endpoints.vertex'),
            'headers' => [
                'Authorization' => 'Bearer '.m3()->activeToken(),
                'Accept' => 'application/json',
                'Content-Type' => 'application/json',
            ],
            'connect_timeout' => 5,
            'timeout' => 5,
        ]);
        return $this->getSale($client, $this->getTaxAreaId($client, $shippingAddress), $part, $linePrice);
    }

    /**
     * @param $client
     * @param $shippingAddress
     * @return array|ArrayAccess|mixed
     */
    private function getTaxAreaId ($client, $shippingAddress) {
        $jsonBody = <<<JSON
{
    "postalAddress": {
        "streetAddress1": "$shippingAddress->addr_1",
        "streetAddress2": "$shippingAddress->addr_2",
        "country": "$shippingAddress->country",
        "mainDivision": "$shippingAddress->state",
        "city": "$shippingAddress->city",
        "postalCode": "$shippingAddress->postal_cd"
    }
}
JSON;

        $response = $client->post(config('m3-config.commands.taxAreaId'), [
            'body' => $jsonBody,
        ]);
        $responseBody = $response->getBody();
        $addressResponse = json_decode($responseBody, true);
        return $this->parseTaxAreaId($addressResponse);
    }

    /**
     * @param $addressLookupResponse
     * @return array|ArrayAccess|mixed
     */
    private function parseTaxAreaId ($addressLookupResponse) {
        /*
         * {
         *      'data': {
         *          'lookupResults': [
         *              {
         *                  'jurisdictions': [...],
         *                  'postalAddresses': [...],
         *                  'statuses': [...],
         *                  'taxAreaId': <tax area ID>,
         *                  'confidenceIndicator': '<confidence number>'
         *              },...
         *          ]
         *      }
         * }
         */
        $addressLookupResults = Arr::get(Arr::get($addressLookupResponse, 'data', []), 'lookupResults', []);
        return Arr::get($addressLookupResults[0], 'taxAreaId');
    }

    /**
     * @param $client
     * @param $taxAreaId
     * @param $part
     * @param $linePrice
     * @return mixed
     */
    private function getSale ($client, $taxAreaId, $part, $linePrice) {
        if (is_null($taxAreaId) || strlen(trim($taxAreaId)) == 0) {
            return [
                'taxResult' => '',
                'calculatedTax' => 0,
            ];
        }
        $companyNumber = config('m3-config.cono');

        $jsonBody = <<<JSON
{
    "saleMessageType": "QUOTATION",
    "seller": {
        "company": "$companyNumber"
    },
    "lineItems": [
        {
            "customer": {
                "destination": {
                    "taxAreaId": $taxAreaId
                }
            },
            "product": {
                "value": "$part->vertexid"
            },
            "unitPrice": $linePrice
        }
    ],
    "transactionType": "SALE"
}
JSON;

        $response = $client->post(config('m3-config.commands.taxLookup'), [
            'body' => $jsonBody,
        ]);
        $responseBody = $response->getBody();
        $saleResponse = json_decode($responseBody, true);
        return $this->parseSale($saleResponse);
    }

    /**
     * @param $saleResponse
     * @return array
     */
    private function parseSale ($saleResponse): array {
        /*
         * {
         *      'data': {
         *          'saleMessage': "QUOTATION",
         *          'seller': {
         *              'company': '750',
         *          },
         *          'subTotal': <total without tax>,
         *          'total': <total with tax>,
         *          'totalTax: <tax without total>,
         *          'lineItems': [
         *              {
         *                  'customer': {
         *                      'destination': {
         *                          'taxAreaId': <tax area id>
         *                      }
         *                  },
         *                  'product': {
         *                      'value': <Vertex product code>
         *                  },
         *                  'quantity': {
         *                      'value': <quantity of product>
         *                  },
         *                  'fairMarketValue': <fair market value unit price>,
         *                  'unitPrice': <unit price>,
         *                  'extendedPrice': <unit price * quantity>,
         *                  'taxes': [
         *                      {
         *                          'jurisdiction': {
         *                              'jurisdictionLevel': '<e.g., "STATE">',
         *                              'jurisdictionId': <id>,
         *                              'value': '<e.g., "INDIANA">'
         *                          },
         *                          'calculatedTax': <tax without total>,
         *                          'effectiveRate': <tax rate in decimal, e.g., 0.07>,
         *                          'taxable': <total taxable price>,
         *                          'imposition': {
         *                              'impositionId': <id>,
         *                              'value': '<e.g., "Gross Retail and Use Tax">'
         *                          },
         *                          'impositionType': {
         *                              'impositionTypeId': <id>,
         *                              'value': '<e.g., "General Sales and Use Tax">'
         *                          },
         *                          'taxRuleId': {
         *                              'value': '<internal id of tax rule>'
         *                          },
         *                          'taxResult': '<e.g., "TAXABLE">',
         *                          'taxType': '<e.g., "SALES">',
         *                          'situs': '<e.g., "DESTINATION">',
         *                          'taxCollectedFromParty': '<e.g., "BUYER">',
         *                          'taxStructure': '<e.g., "SINGLE_RATE">'
         *                      },...
         *                  ],
         *                  'totalTax': <tax without total>
         *              },...
         *          ]
         *      }
         * }
         */
        $lineItems = Arr::get(Arr::get($saleResponse, 'data', []), 'lineItems', []);
        $lineItem = $lineItems[0];
        $taxes = Arr::get($lineItem, 'taxes', []);
        $taxResult = Arr::get($taxes[0], 'taxResult', '');
        $totalTax = Arr::get($lineItem, 'totalTax', 0);
        return [
            'taxResult' => $taxResult,
            'calculatedTax' => $totalTax,
        ];
    }
}