<?php

class ScooterApi extends Api
{
    public $apiName = 'scooter';

    public function indexAction()
    {
        $messge = 'Data not found';
        return $this->response(
            array(
                'error' => $message
            ), 404);
    }

    /**
     * Method GET
     * Get single record (by id)
     * http://DOMAIN/geocode/1
     * @return string
     */
    public function viewAction()
    {
        //id must be the first parameter after /geocode/x
        $id = array_shift($this->requestUri);

        if($id && (int)$id>0){
            $db = new Db();
            $address = Geocode::getAddressById($db->getConnect(), (int)$id);
            if(is_array($address) && count($address)>0){
                return $this->response($address, 200);
            }
        }
        return $this->response(
            array(
                'error'=> 'Data not found'
            ), 404);
    }

    public function createAction()
    {
        $message = "Failed to run scooter directions";
        $addresses = $this->requestParams["addresses"] ?? array();
        $options = $this->requestParams["options"] ?? array();
        try {
            throw new Exception("We are sorry but scooters are not yet launched in your country.  Please check back again soon!");
            if ($addresses==NULL || !is_array($addresses) || count($addresses)<1 || !isset($addresses[0]["address"])) {
                throw new Exception("Invalid input");
            }
            $db = new Db();
            $result = [];
            $input = [];
            foreach ($addresses as $item) {
                if (isset($item["type"]) && $item["type"]>0 && $item["type"]<3) {
                    $input[$item["type"]] = $item;
                }
            }
            if (isset($input[1]) && isset($input[2]) &&
                isset($input[1]["address"]) && isset($input[2]["address"])) {

                list($result, $err) = self::scooter($db, $input);

                if (!is_array($result) || count($result)<1) {
                    throw new Exception($err!=''? $err : 'No scooter option available');
                }
            } else {
                throw new Exception("Invalid address"); 
            }
            if ((isset($options["travel_time"]) && $options["travel_time"]) ||
                (isset($options["quote"]) && $options["quote"]) ||
                (isset($options["route_overlay"]) && $options["route_overlay"])) {
                $options = self::options($db, $input, $result, $options);
            }
            return $this->response(
                array(
                    'data'=>$result,
                    'options'=>$options), 200);
        } catch (Exception $e) {
            error_log(json_encode($e));
            $message = $e->getMessage();
        }
        return $this->response(
            array(
                "error" => $message
            ), 500);
    }

    public function updateAction()
    {
        return $this->response(
            array(
                "error" => "Update error"
            ), 400);
    }

    public function deleteAction() {
        return $this->response(
            array(
                "error" => "Delete error"
            ), 500);
    }

    public function scooter($db, $input) {
        global $savvyext;
        $httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token');
        $oauth2_url = $savvyext->cfgReadChar('system.oauth2_url');
        // Call scooter service
        $gps1 = $input[1]["coordinates"];
        $gps2 = $input[2]["coordinates"];
        $data = http_build_query(
            array(
                'gps' => sprintf("%s,%s,%s,%s",$gps1["lat"],$gps1["lng"],$gps2["lat"],$gps2["lng"]),
                'from' => $input[1]["address"],
                'to' => $input[2]["address"]
            )
        );
        $url = $oauth2_url."scooter?" . $data;
        //error_log($url);
        $opts = array(
            'http' => array(
                'method' => "GET",
                'header'  => 
                    "Content-Type: application/x-www-form-urlencoded\r\n" .
                    "Accept: application/json\r\n" .
                    "Authorization: Server-Token ${httpAuthToken}\r\n",
            ),
            "ssl" => array(
              "verify_peer"=>false,
              "verify_peer_name"=>false,
            )
        );
        $context = stream_context_create($opts);
        $body = file_get_contents($url, false, $context);
        $scooter = json_decode($body,true);
        if (is_array($scooter) && is_array($scooter["data"]) && !isset($scooter["error"])) {
            // Cache the result in DB
            //$scooter["data"]["id"] = Scooter::save($db->getConnect(), $scooter["data"]);
            return array($scooter["data"], NULL);
        } else if (is_array($scooter) && isset($scooter["error"])) {
            $body = $scooter["error"];
        }
        return array(NULL, "Scooter service call error: ".$body);
    }

    public function options($db, $input, $result, $options) {
        if (isset($options["travel_time"]) && $options["travel_time"]) {
            $travel_time = 0;
            foreach ($result as $step) {
                $travel_time += $step["duration"];
            }
            $options["travel_time"] = (int)$travel_time; 
        }
        if (isset($options["quote"]) && $options["quote"] && 
            is_array($result) && count($result)>1 &&
            isset($result[1]["duration"]) && $result[1]["duration"]>0) {

            $scooter_time = $result[1]["duration"]; // 2nd entry is the scooter step
            list($res,$err) = self::quote($db, $scooter_time, 'SG');
            if ($err!=NULL) {
                $options["error"] = $err;
            } else {
                $options["quote"] = $res;
            }
        }
        if (isset($options["route_overlay"]) && $options["route_overlay"]) {
            $options = self::directions($db, $input, $result, $options);
        }
        return $options;
    }

    public function quote($db, $seconds, $country='SG') {
        global $scooterAuthToken, $savvyext;
        // Check local DB cache
        /* list ($res, $err) = Scooter::checkScooterQuote($db->getConnect(), $minutes, $country);
        if (is_array($res) && isset($res[0]["quote"])) {
            return array($res, NULL);
        } */
        // Call scooter quote service
        $data = http_build_query(
            array(
                'minutes' => (int)($seconds/60),
                'country' => $country
            )
        );
        $url = $savvyext->cfgReadChar('microservices.catalog') . "/api/v1/price-quote/?" . $data;
        $opts = array(
            'http' => array(
                'method' => "GET",
                'header'  => 
                    "Content-Type: application/x-www-form-urlencoded\r\n" .
                    "Accept: application/json\r\n" .
                    "Authorization: Server-Token ${scooterAuthToken}\r\n",
            ),
            "ssl" => array(
              "verify_peer"=>false,
              "verify_peer_name"=>false,
            )
        );
        $context = stream_context_create($opts);
        $body = file_get_contents($url, false, $context);
        $scooter = json_decode($body,true);
        if (is_array($scooter) && count($scooter)>0 && isset($scooter[0]["quote"])) {
            // Cache the result in DB
            //$scooter["data"]["id"] = Scooter::saveQuote($db->getConnect(), $scooter);
            return array($scooter, NULL);
        } else if (is_array($scooter) && isset($scooter["error"])) {
            $body = $scooter["error"];
        }
        return array(NULL, "Scooter quote service call error: ".$body);
    }

    public function directions($db, $input, $result, $options) {
        // Walking with waypoints or 3 routes
        $mode='walking';
        $waypoints=[
            $result[1]["data"]["location_start_lat"], $result[1]["data"]["location_start_lng"],
            $result[1]["data"]["location_end_lat"], $result[1]["data"]["location_end_lng"]
        ];
        $fromLat = $input[1]["coordinates"]["lat"];
        $fromLng = $input[1]["coordinates"]["lng"]; 
        $toLat   = $input[2]["coordinates"]["lat"]; 
        $toLng   = $input[2]["coordinates"]["lng"];
        list($res, $err) = GeocodeApi::route(
            $db, $fromLat, $fromLng, $toLat, $toLng, $mode, $waypoints);
        if ($err!=NULL || !is_array($res) || !isset($res["routes"]) || count($res["routes"])<1) {
            $options['error'] = $err!=NULL ? $err : 'No available routes';
            return $options;
        }
        $options["route_overlay"] = [];
        $travel_time = PHP_INT_MAX;
        $travel_distance = PHP_INT_MAX;
        foreach ($res["routes"] as $route) {
            $r = GeocodeApi::processRoute($route);
            if ($travel_time>$r['duration']) {
                $travel_time = $r['duration'];
                $travel_distance = $r['distance'];
            } 
            $options["route_overlay"][] = $r;
        }
        // ["route_overlay"]
        return $options;
    }
}
