<?php
namespace App\Library;
use App\Core\Service\Logger;
use App\Service\Api;

class Shiprocket  
{   
    private $api = null;
    private $token;
    private $login_id;
    private $api_key_password;
    private $headers;
    private $envirnment;
    private $access_token;
    public function __construct(Array $settings) {
        $this->envirnment = 'development'; 
        $this->api = new Api();
        $this->login_id = !empty($settings['login_id']) ? $settings['login_id'] : '';
        $this->api_key_password = !empty($settings['api_key_password']) ? $settings['api_key_password'] : '';
        $this->token = !empty($settings['token']) ? $settings['token'] : '';
        $this->access_token = !empty($settings['access_token']) ? $settings['access_token'] : '';
        $this->headers = [];
    }
    
    function url($url=""){
		$mode['development'] = "https://apiv2.shiprocket.in/v1/external/".$url;
		$mode['production']  = "https://apiv2.shiprocket.in/v1/external/".$url;
		return $mode[$this->envirnment];
	}

    private function checkConfiguration() {
        try {
            if(empty($this->token)) {
                throw new \Exception("Shiprocket configuration is incomplete. Provide all required settings.(token, pincode_servicability_url and so on.)");
            }
            return true;
        } catch(\Exception $e) {
            Logger::error($e->getMessage(), ['File' => $e->getFile(), 'Line'=>$e->getLine()]);
            return false;
        }
    }

    private function getToken() { 
        try {
            $url = $this->url("auth/login");
            $headers = ['Content-Type: application/json'];
            $payload = json_encode(["email"=>$this->login_id, "password"=>$this->api_key_password]);
            
            $callrs = $this->api->call($url, 'POST', $headers, $payload);
            if(empty($callrs['status'])) {
                throw new \Exception($callrs['error']);
            }
            if(empty($callrs['data'])) {
                throw new \Exception("No response from Shiprocket Get Token API");
            }
            $curlData =  json_decode($callrs['data'], true);
        
            if(!empty($curlData['token'])){
                $this->headers = array('Authorization' =>  'Bearer '.$curlData['token'], 'Content-Type' => 'application/json');
                $return = array('status'=>true, 'token'=>$curlData['token']);			
            } else {
                $return = array('status'=>true, 'message'=>!empty($curlData['message'])?$curlData['message']:"There is some technical issue to create token ");
            } 
            return $return;
        } catch(\Exception $e) {
            Logger::error($e->getMessage(), ['File' => $e->getFile(), 'Line'=>$e->getLine()]);
            return ["status"=>false, "error"=>$e->getMessage()];
        }
	}

    private function addOrder($payload) {
        try {
            $tokenrs = $this->getToken();
            if(empty($tokenrs['status'])) {
                throw new \Exception($tokenrs['error']);
            }
            if(empty($tokenrs['token'])) {
                throw new \Exception($tokenrs['message']);
            }
            $url = $this->url("orders/create/adhoc");
            $headers = ['Content-Type' => 'application/json', 'Authorization' => 'Bearer '.$tokenrs['token']];
            $callrs = $this->api->call($url, 'POST', $headers, $payload);
            if(empty($callrs['status'])) {
                try {
                    $err = json_decode($callrs['error'], true);
                    if($err['message']) {
                        return ["status"=>false, "error"=>$err['message']];
                    }
                } catch(\Exception $e) {
                } finally {
                    throw new \Exception($callrs['error']);
                }
            }
            
            if(empty($callrs['data'])) {
                throw new \Exception("No response from Shiprocket addOrder API");
            }
            $curlData =  json_decode($callrs['data'], true);
            if(!empty($curlData['shipment_id'])) {
                return array('status'=>true,'shipment_id'=>$curlData['shipment_id']);
            } else {
                throw new \Exception(!empty($curlData['message'])?$curlData['message']:"There is some technical issue to create order");
            }
        } catch(\Exception $e) {
            Logger::error($e->getMessage(), ['File' => $e->getFile(), 'Line'=>$e->getLine()]);
            return ["status"=>false, "error"=>$e->getMessage()];
        }
    }

    function createDocketNo($order, $item, $data) {
        try {
            $resp = $this->prepareDataForDocketNo($order, $item, $data);
            if(empty($resp['status'])) {
                return ["status"=>false, "error"=>$resp['error']];
            }
            $payload  = json_encode($resp['data']);
            // echo "<pre>"; print_r($payload); exit;

            $addrs = $this->addOrder($payload);
            if(empty($addrs['status'])) {
                throw new \Exception($addrs['error']);
            }
            $url = $this->url("courier/assign/awb");
            
            $callrs = $this->api->call($url, 'POST', $this->headers, json_encode(['shipment_id'=>$addrs['shipment_id']]));
            if(empty($callrs['status'])) {
                try {
                    $err = json_decode($callrs['error'], true);
                    if($err['message']) {
                        return ["status"=>false, "error"=>$err['message']];
                    }
                } catch(\Exception $e) {
                    Logger::error($e->getMessage(), ['File' => $e->getFile(), 'Line'=>$e->getLine()]);
                    throw new \Exception($callrs['error']);
                }
            }
            if(empty($callrs['data'])) {
                throw new \Exception("No response from Delhivery Create Docket No. API");
            }
            $curlData =  json_decode($callrs['data'], true);
            if(!empty($curlData['awb_assign_status'])) {
                return array('status'=>true, 'data'=>$curlData['response']['data']);
            } else {
                throw new \Exception(!empty($curlData['message'])?$curlData['message']:"There is some technical issue to get AWB number");
            }
        } catch(\Exception $e) {
            Logger::error($e->getMessage(), ['File' => $e->getFile(), 'Line'=>$e->getLine()]);
            return ["status"=>false, "error"=>$e->getMessage()];
        }
    }

    public function trackDocketNo(String $docket_no, $courier_routing_code  = '') {
        try {
            if(empty($docket_no)) {
                throw new \Exception("Provide Docket No to track the shipment for Shiprocket");
            }
            if(!$this->checkConfiguration()) {
                throw new \Exception("Delhivery configuration is incomplete. Provide all required settings.(token, pincode_servicability_url and so on.)");
            }
            $tokenrs = $this->getToken();
            if(empty($tokenrs['status'])) {
                throw new \Exception($tokenrs['error']);
            }
            if(empty($tokenrs['token'])) {
                throw new \Exception($tokenrs['message']);
            }
            $url = $this->url("courier/track/awb/".$docket_no);
            $headers = ['Content-Type: application/json', 'Authorization: Bearer '.$tokenrs['token']];
            $callrs = $this->api->call($url, 'GET', $headers, '');
            if(empty($callrs['status'])) {
                throw new \Exception($callrs['error']);
            }
            if(empty($callrs['data'])) {
                throw new \Exception("No response from BlueDart track courier API");
            }
            $curlData =  json_decode($callrs['data'], true); 
            if(empty($curlData['tracking_data'])) {
                throw new \Exception("No tracking data found for the provided Docket No.");
            }
            if(!empty($curlData['tracking_data']['error'])) {
                throw new \Exception($curlData['tracking_data']['error']);
            }
            if(empty($curlData['tracking_data']['track_status'])) {
                throw new \Exception("No tracking status found for the provided Docket No.");
            } 
            $resp = $this->prepareCoutrierTrackingResponse($docket_no, $curlData['tracking_data'], $courier_routing_code);
            if(empty($resp['status'])) {
                throw new \Exception($resp['error']);
            }
            return array('status' => true, 'data' => $resp['data']);
        } catch(\Exception $e) {
            Logger::error($e->getMessage(), ['File' => $e->getFile(), 'Line'=>$e->getLine()]);
            return ["status"=>false, "error"=>$e->getMessage()];
        }
    }

    private function prepareDataForDocketNo($order, $items, $data) {
        try {
            // echo "<pre>"; print_r($order['customer_billing_address']); exit;
            $customer = json_decode($order['customer_detail'], true);
            $customer_name_arr = explode(" ", $customer['customer_name']);
            $itemDetail = json_decode($items['item_detail'], true);
            
            $item = [];
            $item["name"] = $data['courier_product_name'];
            $item["sku"] = $itemDetail['item_code'];
            $item["units"] = $order['total_item_qty'];
            $item["selling_price"] = round($itemDetail['rate']);
            $item["discount"] = 0;
            $item["tax"] = $itemDetail['including_tax'];
            $item["hsn"] = $items['hsn_code'];

            $srData = [];
            $srData['order_items'] = [$item];

            $srData["order_id"] = $order['id'];
            $srData["order_date"] = $order['booking_time'];
            
            $srData["pickup_location"] = "Home"; //"WORLDWEB";fsdf
            $srData["channel_id"] = "";
            $srData["comment"] = "";
            $srData["billing_customer_name"] = $customer_name_arr[0] ? $customer_name_arr[0] : "NaN";
            $srData["billing_last_name"] = isset($customer_name_arr[1]) ? $customer_name_arr[1] : "";
            $srData["billing_address"] = !empty($order['customer_billing_address']['address']) ? str_replace("\r\n", " ", $order['customer_billing_address']['address']) : "NaN";
            $srData["billing_address_2"] = "";
            $srData["billing_city"] = !empty($order['customer_billing_address']['address_city_name']) ? $order['customer_billing_address']['address_city_name'] : "";
            $srData["billing_pincode"] = !empty($order['customer_billing_address']['address_pincode']) ? (int) $order['customer_billing_address']['address_pincode'] : "";
            $srData["billing_state"] = !empty($order['customer_billing_address']['address_state_name']) ? $order['customer_billing_address']['address_state_name'] : "NaN";
            $srData["billing_country"] = $order['branch_country_name'];
            $srData["billing_email"] = $customer['email_id'] ? $customer['email_id'] : "";
            $srData["billing_phone"] = $customer['mobile_number'] ? $customer['mobile_number'] : '';
            $srData["shipping_is_billing"] = 1;
            $srData["shipping_customer_name"] = $srData["billing_customer_name"];
            $srData["shipping_last_name"] = $srData["billing_last_name"];
            $srData["shipping_address"] = $srData["billing_address"];
            $srData["shipping_address_2"] = $srData["billing_address_2"];
            $srData["shipping_city"] = $srData["billing_city"];
            $srData["shipping_pincode"] = $srData["billing_pincode"];
            $srData["shipping_country"] = $srData["billing_country"];
            $srData["shipping_state"] = $srData["billing_state"];
            $srData["shipping_email"] = $srData["billing_email"];
            $srData["shipping_phone"] = $srData["billing_phone"];

            $srData["payment_method"] = $data['courier_payment_mode'] == 'p' ? 'Prepaid' : 'COD';
            $srData["shipping_charges"] = round($order['courier_charges']);
            $srData["giftwrap_charges"] = "";
            $srData["transaction_charges"] = "";
            $srData["total_discount"] = round($order['discount_amt'] + $order['additional_discount']);
            $srData["sub_total"] = round($order['net_amt'] + $srData["total_discount"]);
            $srData["length"] = $data['courier_length'];
            $srData["breadth"] = $data['courier_breath'];
            $srData["height"] = $data['courier_height'];
            $srData["weight"] = $data['courier_weight'];

            return ["status"=>true, "data"=>$srData];
        } catch(\Exception $e) {
            Logger::error($e->getMessage(), ['File' => $e->getFile(), 'Line'=>$e->getLine()]);
            return ["status"=>false, "error"=>$e->getMessage()];
        }    
    }

    private function prepareCoutrierTrackingResponse($docket_number, $tracking_data,  $courier_routing_code) {
        try {
            $shipment_track = end($tracking_data['shipment_track']);
			$last_activities = end($tracking_data['shipment_track_activities']);
            $activities = $tracking_data['shipment_track_activities'];
            $dataArray = array();
            $dataArray['DOCKNO'] = $shipment_track['awb_code'];
			$dataArray['EVENTDATE'] = $last_activities['date'];
			$dataArray['ORIGIN'] = $shipment_track['origin'];
			$dataArray['DESTINATION'] = $shipment_track['destination'];
			if (!empty($courier_routing_code)) {
				$dataArray['DESTINATION'] = $courier_routing_code;
			}
			$dataArray['PINCODE'] = "---";
			$dataArray['CURRENT_CITY'] = $last_activities['location'];
			$dataArray['CURRENT_STATUS'] = $shipment_track['current_status'];
			foreach ($activities as $i => $row) {
                $activity = [];
				$activity['CURRENT_CITY'] = $row['location'];
				$activity['EVENTDATE'] = date('d-m-Y', strtotime($row['date']));
				$activity['EVENTTIME'] = date('H:i:s', strtotime($row['date']));
				$activity['NEXT_LOCATION'] = isset($activities[$i + 1]) ? $activities[$i + 1]['location'] : '-';
				$activity['CURRENT_STATUS'] = $row['activity'];
				$dataArray['Detail'][] = $activity;
			}
            return ["status"=>true, "data"=>$dataArray];
        } catch(\Exception $e) {
            Logger::error($e->getMessage(), ['File' => $e->getFile(), 'Line'=>$e->getLine()]);
            return ["status"=>false, "error"=>$e->getMessage()];
        }
    }
}