<?php

class Tracking_UPS {

    /**
     *
     * @param string $code
     * @return \TrackingInfo
     * @throws TrackingException
     */
    public static function track(string $code, string $carrier = ""): TrackingInfo {
        $barcode = new TrackingBarcode($code);


        try {
            $response = UPSAPIs::getAPIRequest("track/v1/details/$code?locale=en_US&returnSignature=false&returnMilestones=false&returnPOD=false");

            $result = json_decode($response, true);

            if (!empty($result["trackResponse"]["shipment"]) && count($result["trackResponse"]["shipment"]) > 0) {
                $trackinfo = $result["trackResponse"]["shipment"][0];
            } else {
                throw new TrackingException("No tracking details found.");
            }
            //exitWithJson($trackinfo);
        } catch (TrackingException $ex) {
            throw $ex;
        } catch (Exception $ex) {
            throw new TrackingException("There was a server problem. This code cannot be tracked right now.");
        }

        $info = new TrackingInfo();
        if (!empty($trackinfo["package"]["trackingNumber"])) {
            $info->setCode($trackinfo["package"]["trackingNumber"]);
        } else if (is_array($trackinfo["package"])) {
            // More than one linked package in one shipment, get rid of the extra and make the
            // schema match what we expect
            $package = [];
            for ($i = 0; $i < count($trackinfo["package"]); $i++) {
                if ($trackinfo["package"][$i]["trackingNumber"] == $code) {
                    $info->setCode($trackinfo["package"][$i]["trackingNumber"]);
                    $package = $trackinfo["package"][$i];
                    $trackinfo["package"] = $package;
                    break;
                }
            }
        }

        $info->setCarrier("ups");
        $info->setService(new Service($trackinfo["package"]["service"]["code"], $trackinfo["package"]["service"]["description"]));
        $info->setCarrierAttributionText(CarrierAssets::getAttribution(Carriers::getCarrierCode($info->getCarrier())));
        $info->setCarrierLogo(CarrierAssets::getLogo(Carriers::getCarrierCode($info->getCarrier())));

        if (count($trackinfo["package"]["activity"]) > 0) {
            // If there's only one entry, it might not be an array
            if (isset($trackinfo["package"]["activity"][0])) {
                $current = $trackinfo["package"]["activity"][0];
            } else {
                $current = $trackinfo["package"]["activity"];
            }
            $current_status = new TrackingEntry(
                    TrackingStatus::UPSEventTypeToStatus($current["status"]["type"]),
                    trim($current["status"]["description"] ?? "Unknown"),
                    DateTime::createFromFormat('Ymd His', "$current[date] $current[time]")->format("c")
            );

            $current_location = new Location();
            $current_location->city = $current["location"]["address"]["city"] ?? "";
            $current_location->state =  $current["location"]["address"]["stateProvince"] ?? "";
            $current_location->zip =  $current["location"]["address"]["postalCode"] ?? "";
            $current_location->country =  $current["location"]["address"]["countryCode"] ?? "";
            $current_status->setLocation($current_location);

            $info->setCurrentStatus($current_status);
        }

        foreach ($trackinfo["package"]["packageAddress"] as $address) {
            switch ($address["type"]) {
                case "DESTINATION": // ShipTo Address
                    $to = new Location();
                    $to->city = $address["address"]["city"] ?? "";
                    $to->state = $address["address"]["stateProvince"] ?? "";
                    $to->zip = $address["address"]["postalCode"] ?? "";
                    $to->country = $address["address"]["countryCode"] ?? "";
                    $info->setTo($to);
                    break;
                case "ORIGIN":
                    $from = new Location();
                    $from->city = $address["address"]["city"] ?? "";
                    $from->state = $address["address"]["stateProvince"] ?? "";
                    $from->zip = $address["address"]["postalCode"] ?? "";
                    $from->country = $address["address"]["countryCode"] ?? "";
                    $info->setFrom($from);
            }
        }
//
//        $from = new Location();
//        $from->city = (string) $trackinfo->OriginCity ?? "";
//        $from->state = (string) $trackinfo->OriginState ?? "";
//        $from->zip = (string) $trackinfo->OriginZip ?? "";
//        $from->country = (string) $trackinfo->OriginCountryCode ?? "";
//
//        $info->setFrom($from);
        // Only one entry, so put it in itself so the loop works
        if (!isset($trackinfo["package"]["activity"][0])) {
            $trackinfo["package"]["activity"] = [
                $trackinfo["package"]["activity"]
            ];
        }
        foreach ($trackinfo["package"]["activity"] as $history) {
            $location = new Location();
            $location->city = $history["location"]["address"]["city"] ?? "";
            $location->state = $history["location"]["address"]["stateProvince"] ?? "";
            $location->zip = $history["location"]["address"]["postalCode"] ?? "";
            $location->country = $history["location"]["address"]["countryCode"] ?? "";
            if (!empty($history["date"]) && !empty($history["time"])) {
                $datetimestring = DateTime::createFromFormat('Ymd His', "$history[date] $history[time]")->format("c");
            } else if (!empty($history["date"])) {
                $datetimestring = DateTime::createFromFormat('Ymd His', "$history[date]")->format("c");
            } else {
                $datetimestring = "";
            }
            $info->appendHistoryEntry(new TrackingEntry(
                            TrackingStatus::UPSEventTypeToStatus($history["status"]["type"]),
                            trim($history["status"]["description"] ?? "Unknown"),
                            $datetimestring,
                            $location
            ));
        }

        return $info;
    }

}
