<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\DB;
use Validator;
use App\Responses;
use App\Helper;
use App\Models\Zone;
use App\Models\Users;
use App\Models\Clients;
use App\Models\Region;
use App\Models\Orders;
use App\Models\OrdersDrops;
// use App\Models\OrdersPckDrop;
use App\Models\OrdersAItems;
use App\Models\UserLogs;


class ZoneController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function view_zone(Request $req)
    {
		$log = [
			"module" => "Zone",
			"action" => "View",
			"desc" => "Open Zone menu",
		];
		UserLogs::insert($req->auth->uid, $log);
        return view("menu_v1.zone");
    }

    public function view_zone_add(Request $req)
    {
        $data = [
            "types" => Zone::listTypes(),
            "workflows" => Zone::listWorkflows(),
            "boundarys" => Zone::listBoundarys(),
            "provs" => Region::listProv(),
        ];

        if ($req->auth->role == Users::ROLE_SUPERADMIN) {
            $data["is_su"] = 1;
            $data["clients"] = Clients::select2Client();
        } elseif ($req->auth->role == Users::ROLE_ADMIN) {
            $data["is_su"] = 1;
            $data["clients"] = Clients::select2Client();
        } else {
            $data["clients"] = [];
            $data["is_su"] = 0;
        }

        return view("menu_v1._addZone", $data);
    }

    public function view_zone_edit(Request $req, $zid)
    {
        $input = [
            "zid" => $zid,
        ];
        $rulesInput = [
            "zid" => "required|integer|not_in:0",
        ];

        // validasi input
        $isValidInput = Validator::make($input, $rulesInput);
        if (!$isValidInput->passes()) {
            $apiResp = Responses::bad_input($isValidInput->messages()->first());
            return new Response($apiResp, $apiResp["meta"]["code"]);
        }

        $zone = Zone::showZoneById($zid);
        if (count($zone) < 1) {
            $apiResp = Responses::not_found("zone not found");
            return new Response($apiResp, $apiResp["meta"]["code"]);
        }
        if ($zone[0]->boundary_bounds) {
            $zone[0]->boundary_bounds = json_decode($zone[0]->boundary_bounds);
        }
        if ($zone[0]->boundary_latlngs) {
            $zone[0]->boundary_latlngs = json_decode($zone[0]->boundary_latlngs);
        }
        unset($zone[0]->boundary_points);

        $data = [
            "zone" => $zone[0],
            "types" => Zone::listTypes(),
            "workflows" => Zone::listWorkflows(),
            "boundarys" => Zone::listBoundarys(),
            "provs" => Region::listProv(),
        ];

        if ($req->auth->role == Users::ROLE_SUPERADMIN) {
            $data["is_su"] = 1;
            $data["clients"] = Clients::select2Client();
        } elseif ($req->auth->role == Users::ROLE_ADMIN) {
            $data["is_su"] = 1;
            $data["clients"] = Clients::select2Client();
        } else {
            $data["clients"] = [];
            $data["is_su"] = 0;
        }

        $arr_zone = (array) $data["zone"];
        $data["arr_zone"] = json_encode($arr_zone);

        return view("menu_v1._edtZone", $data);
    }

    public function view_user_checker_zone_edit(Request $req)
    {
        $input = [
            "zid" => $req->zid,
            "ord_code" => $req->ord_code,
        ];
        $rulesInput = [
            "zid" => "required|integer|not_in:0",
            "ord_code" => "required|string|max:12",
        ];

        // validasi input
        $isValidInput = Validator::make($input, $rulesInput);
        if (!$isValidInput->passes()) {
            $apiResp = Responses::bad_input($isValidInput->messages()->first());
            return new Response($apiResp, $apiResp["meta"]["code"]);
        }

        $zone = Zone::showZoneById($req->zid);
        if (count($zone) < 1) {
            $apiResp = Responses::not_found("zone not found");
            return new Response($apiResp, $apiResp["meta"]["code"]);
        }
        if ($zone[0]->boundary_bounds) {
            $zone[0]->boundary_bounds = json_decode($zone[0]->boundary_bounds);
        }
        if ($zone[0]->boundary_latlngs) {
            $zone[0]->boundary_latlngs = json_decode($zone[0]->boundary_latlngs);
        }
        unset($zone[0]->boundary_points);

        $orders = Orders::showOrder([
            "code" => $req->ord_code,
            // 'get_stts_checker' => 1,
            // 'get_prefer_type_truck' => 1,
            // 'get_checker_data' => 1,
            // 'get_client_pt' => 1,
            // 'get_accidents' => 1,
            "couple_pck_drop" => 1,
            // 'get_user_aprv_pck' => 1,
            // 'get_user_aprv_pck' => 1,
            "group_by" => "ord.id",
        ]);
        if (count($orders) < 1) {
            return redirect(url()->previous());
        }

        $data = [
            "zone" => $zone[0],
            "order" => $orders[0],
            "types" => Zone::listTypes(),
            "workflows" => Zone::listWorkflows(),
            "boundarys" => Zone::listBoundarys(),
            "provs" => Region::listProv(),
        ];

        $data["clients"] = Clients::select2Client();

        $arr_zone = (array) $data["zone"];
        $data["arr_zone"] = json_encode($arr_zone);

        return view("menu_v2.Checker._edtZone", $data);
    }

    /**
     * API
     */

    public function api_list_zones(Request $req)
    {
        try {
            $now = time();
            $input = [];
            $rulesInput = [];

            // validasi input
            // $isValidInput = Validator::make($input, $rulesInput);
            // if (!$isValidInput->passes()) {
            // 	$apiResp = Responses::bad_input($isValidInput->messages()->first());
            // 	return new Response($apiResp, $apiResp['meta']['code']);
            // }

            $filter = [];
            if ($req->cptid) {
                $filter["company"] = $req->cptid;
            }
            if ($req->status) {
                $filter["is_active"] = $req->status;
            }
            $list = Zone::listZones($req->auth, $filter);

            foreach ($list as $key => $row) {
                $list[$key]->DT_RowIndex = $key + 1;
                $list[$key]->action = "-";
                unset($list[$key]->boundary_points);
            }

            $apiResp = Responses::success("success list zones");
            $apiResp["data"] = $list;
            $apiResp["count"] = count($list);
            return new Response($apiResp, $apiResp["meta"]["code"]);
        } catch (\Exception $e) {
            $apiResp = Responses::error($e->getMessage());
            return new Response($apiResp, $apiResp["meta"]["code"]);
        }
    }

    public function api_show_zone(Request $req, $zid)
    {
        try {
            $now = time();

            $input = [
                "zid" => $zid,
            ];
            $rulesInput = [
                "zid" => "required|integer|not_in:0",
            ];

            // validasi input
            $isValidInput = Validator::make($input, $rulesInput);
            if (!$isValidInput->passes()) {
                $apiResp = Responses::bad_input($isValidInput->messages()->first());
                return new Response($apiResp, $apiResp["meta"]["code"]);
            }

            $zone = Zone::showZoneById($zid);
            if (count($zone) < 1) {
                $apiResp = Responses::not_found("zone not found");
                return new Response($apiResp, $apiResp["meta"]["code"]);
            }

            $apiResp = Responses::success("success get detail zone");
            $apiResp["data"] = $zone[0];
            return new Response($apiResp, $apiResp["meta"]["code"]);
        } catch (\Exception $e) {
            $apiResp = Responses::error($e->getMessage());
            return new Response($apiResp, $apiResp["meta"]["code"]);
        }
    }

    public function api_add_zone(Request $req)
    {
        try {
            $now = time();

            $input = [
                "zone_name" => $req->zone_name,
                "zone_client" => $req->zone_client,
                "zone_type" => $req->zone_type,
                "workflow_zone_type" => $req->workflow_zone_type,
                // "shiptocode" => $req->shiptocode,
                // "prid" => $req->prid,
                // "ktid" => $req->ktid,
                // "kcid" => $req->kcid,
                // "klid" => $req->klid,
                "fulladdress" => $req->fulladdress,
                "status" => $req->status,
                "boundary_hex_color" => $req->boundary_hex_color,
                "boundary_type" => $req->boundary_type,
                "boundary_latlngs" => $req->boundary_latlngs,
                "boundary_bounds" => $req->boundary_bounds,
                "boundary_radius" => $req->boundary_radius,
                "boundary_diameter" => $req->boundary_diameter,
                "boundary_area" => $req->boundary_area, // square meter
                "boundary_ha" => $req->boundary_ha, // hectare
            ];
            $rulesInput = [
                "zone_name" => "required|string|max:255",
                "zone_client" => "nullable|integer|not_in:0",
                "zone_type" => "required|integer|not_in:0",
                "workflow_zone_type" => "required|integer|not_in:0",
                // "shiptocode" => "string|min:5|max:6",
                // "prid" => "required|numeric",
                // "ktid" => "required|numeric",
                // "kcid" => "required|numeric",
                // "klid" => "required|numeric",
                "fulladdress" => "required|string|min:55",
                "status" => "required|integer|not_in:0",
                "boundary_hex_color" => "required|string|min:7|max:7",
                "boundary_type" => "required|string|max:25",
                "boundary_latlngs" => "required|array",
                "boundary_latlngs.*.lat" => "required",
                "boundary_latlngs.*.lng" => "required",
                "boundary_bounds" => "nullable|array",
                "boundary_radius" => "nullable|numeric",
                "boundary_diameter" => "nullable|numeric",
                "boundary_area" => "nullable|numeric",
                "boundary_ha" => "nullable|numeric",
            ];

            // validasi input
            $isValidInput = Validator::make($input, $rulesInput);
            if (!$isValidInput->passes()) {
                $apiResp = Responses::bad_input($isValidInput->messages()->first());
                return new Response($apiResp, $apiResp["meta"]["code"]);
            }

            $uniqName = Zone::getZoneByName($req->zone_name);
            if (count($uniqName) > 0) {
                $apiResp = Responses::bad_request("zone name has been used");
                return new Response($apiResp, $apiResp["meta"]["code"]);
            }

            $user = Users::getUserById($req->auth->uid);

            DB::beginTransaction();

            $insZone = [
                "name" => $req->zone_name,
                "type" => $req->zone_type,
                "workflow_type" => $req->workflow_zone_type,
                "shiptocode" => "123456",
                "prid" => "123456",
                "ktid" => "123456",
                "kcid" => "123456",
                "klid" => "123456",
                "fulladdress" => $req->fulladdress,
                "boundary_type" => $req->boundary_type,
                "boundary_hex_color" => strtoupper($req->boundary_hex_color),
                "boundary_latlngs" => json_encode($req->boundary_latlngs),
                "boundary_bounds" => $req->boundary_bounds ? json_encode($req->boundary_bounds) : null, // $req->boundary_bounds ?? null,
                "boundary_radius" => $req->boundary_radius ?? 0,
                "boundary_diameter" => $req->boundary_diameter ?? 0,
                "boundary_area" => $req->boundary_area ?? 0,
                "boundary_ha" => $req->boundary_ha ?? 0,
                "status" => $req->status,
                "client_group_id" => $req->zone_client ?? ($user[0]->client_group_id ?? null),
                "crt" => $now,
                "crt_by" => $req->auth->uid,
                "updt" => $now,
                "updt_by" => $req->auth->uid,
            ];

            // $insZone['boundary_points'] = DB::raw("ST_GeomFromText('POINT($req->lng $req->lat)')");
            $insZone["boundary_points"] = "ST_GeomFromText('MULTIPOINT(";

            foreach ($req->boundary_latlngs as $key => $val) {
                $insZone["boundary_points"] .= $val["lng"] . " " . $val["lat"] . ", ";
            }
            $insZone["boundary_points"] = substr($insZone["boundary_points"], 0, -2); // remove 2 last character
            $insZone["boundary_points"] .= ")')";
            $insZone["boundary_points"] = DB::raw($insZone["boundary_points"]);

            $zoneId = Zone::addZone($insZone);

            $apiResp = Responses::created("success add new zone");

			$log = [
				"module" => "Zone",
				"action" => "Create",
				"desc" => "Add Zone ".$req->zone_name,
			];
			UserLogs::insert($req->auth->uid, $log);

            DB::commit();
            return new Response($apiResp, $apiResp["meta"]["code"]);
        } catch (\Exception $e) {
            DB::rollBack();
            $apiResp = Responses::error($e->getMessage());
            return new Response($apiResp, $apiResp["meta"]["code"]);
        }
    }

    public function api_edit_zone(Request $req, $zid)
    {
        try {
            $now = time();

            $input = [
                "zone_name" => $req->zone_name,
                "zone_client" => $req->zone_client,
                "zone_type" => $req->zone_type,
                "workflow_zone_type" => $req->workflow_zone_type,
                // "shiptocode" => $req->shiptocode,
                // "prid" => $req->prid,
                // "ktid" => $req->ktid,
                // "kcid" => $req->kcid,
                // "klid" => $req->klid,
                "fulladdress" => $req->fulladdress,
                "status" => $req->status,
                "boundary_hex_color" => $req->boundary_hex_color,
                "boundary_type" => $req->boundary_type,
                "boundary_latlngs" => $req->boundary_latlngs,
                "boundary_bounds" => $req->boundary_bounds,
                "boundary_radius" => $req->boundary_radius,
                "boundary_diameter" => $req->boundary_diameter,
                "boundary_area" => $req->boundary_area, // square meter
                "boundary_ha" => $req->boundary_ha, // hectare
            ];
            $rulesInput = [
                "zone_name" => "required|string|max:255",
                "zone_client" => "nullable|integer|not_in:0",
                "zone_type" => "required|integer|not_in:0",
                "workflow_zone_type" => "required|integer|not_in:0",
                // "shiptocode" => "required|string|min:5|max:6",
                // "prid" => "required|numeric",
                // "ktid" => "required|numeric",
                // "kcid" => "required|numeric",
                // "klid" => "required|numeric",
                "fulladdress" => "required|string|min:55",
                "status" => "required|integer|not_in:0",
                "boundary_hex_color" => "required|string|min:7|max:7",
                "boundary_type" => "required|string|max:25",
                "boundary_latlngs" => "required|array",
                "boundary_latlngs.*.lat" => "required",
                "boundary_latlngs.*.lng" => "required",
                "boundary_bounds" => "nullable|array",
                "boundary_radius" => "nullable|numeric",
                "boundary_diameter" => "nullable|numeric",
                "boundary_area" => "nullable|numeric",
                "boundary_ha" => "nullable|numeric",
            ];

            // validasi input
            $isValidInput = Validator::make($input, $rulesInput);
            if (!$isValidInput->passes()) {
                $apiResp = Responses::bad_input($isValidInput->messages()->first());
                return new Response($apiResp, $apiResp["meta"]["code"]);
            }

            $zone = Zone::showZoneById($zid);
            if (count($zone) < 1) {
                $apiResp = Responses::not_found("zone not found");
                return new Response($apiResp, $apiResp["meta"]["code"]);
            }

            $uniqName = Zone::getZoneByName($req->zone_name);
            if (count($uniqName) > 0) {
                $notSameUser = 1;
                foreach ($uniqName as $key => $row) {
                    if ($row->id == $zid) {
                        $notSameUser = 0;
                    }
                }
                if ($notSameUser) {
                    $apiResp = Responses::bad_request("zone name has been used");
                    return new Response($apiResp, $apiResp["meta"]["code"]);
                }
            }

            $user = Users::getUserById($req->auth->uid);

            DB::beginTransaction();

            $updtZone = [
                "name" => $req->zone_name,
                "type" => $req->zone_type,
                "workflow_type" => $req->workflow_zone_type,
                "shiptocode" => "123456",
                "prid" => "123456",
                "ktid" => "123456",
                "kcid" => "123456",
                "klid" => "123456",
                "fulladdress" => $req->fulladdress,
                "boundary_type" => $req->boundary_type,
                "boundary_hex_color" => strtoupper($req->boundary_hex_color),
                "boundary_latlngs" => json_encode($req->boundary_latlngs),
                "boundary_bounds" => $req->boundary_bounds ? json_encode($req->boundary_bounds) : null, // $req->boundary_bounds ?? null,
                "boundary_radius" => $req->boundary_radius ?? 0,
                "boundary_diameter" => $req->boundary_diameter ?? 0,
                "boundary_area" => $req->boundary_area ?? 0,
                "boundary_ha" => $req->boundary_ha ?? 0,
                "status" => $req->status,
                "client_group_id" => $req->zone_client ?? ($user[0]->client_group_id ?? null),
                "updt" => $now,
                "updt_by" => $req->auth->uid,
            ];

            // $updtZone['boundary_points'] = DB::raw("ST_GeomFromText('POINT($req->lng $req->lat)')");
            $updtZone["boundary_points"] = "ST_GeomFromText('MULTIPOINT(";

            foreach ($req->boundary_latlngs as $key => $val) {
                $updtZone["boundary_points"] .= $val["lng"] . " " . $val["lat"] . ", ";
            }
            $updtZone["boundary_points"] = substr($updtZone["boundary_points"], 0, -2); // remove 2 last character
            $updtZone["boundary_points"] .= ")')";
            $updtZone["boundary_points"] = DB::raw($updtZone["boundary_points"]);

            Zone::updateZone($zid, $updtZone);

			$log = [
				"module" => "Zone",
				"action" => "Update",
				"desc" => "Update Zone ".$req->zone_name,
			];
			UserLogs::insert($req->auth->uid, $log);

			DB::commit();

            $apiResp = Responses::success("success update zone");
            return new Response($apiResp, $apiResp["meta"]["code"]);
        } catch (\Exception $e) {
            DB::rollBack();
            $apiResp = Responses::error($e->getMessage());
            return new Response($apiResp, $apiResp["meta"]["code"]);
        }
    }

    public function api_del_zone(Request $req, $zid)
    {
        try {
            $now = time();

            $input = [
                "zid" => $zid,
            ];
            $rulesInput = [
                "zid" => "required|integer|not_in:0",
            ];

            // validasi input
            $isValidInput = Validator::make($input, $rulesInput);
            if (!$isValidInput->passes()) {
                $apiResp = Responses::bad_input($isValidInput->messages()->first());
                return new Response($apiResp, $apiResp["meta"]["code"]);
            }

            $zone = Zone::showZoneById($zid);
            if (count($zone) < 1) {
                $apiResp = Responses::not_found("zone not found");
                return new Response($apiResp, $apiResp["meta"]["code"]);
            }

            DB::beginTransaction();

            Zone::updateZone($zid, [
                "dlt" => $now,
                "dlt_by" => $req->auth->uid,
            ]);
			
			$log = [
				"module" => "Zone",
				"action" => "Delete	",
				"desc" => "Delete Zone ".$zone[0]->name,
			];
			UserLogs::insert($req->auth->uid, $log);

            DB::commit();

            $apiResp = Responses::success("success delete zone");
            return new Response($apiResp, $apiResp["meta"]["code"]);
        } catch (\Exception $e) {
            DB::rollBack();
            $apiResp = Responses::error($e->getMessage());
            return new Response($apiResp, $apiResp["meta"]["code"]);
        }
    }

    public function api_list_client_zones(Request $req)
    {
        try {
            // cptid (client_group_id / client_pt_id / company_id)
            $now = time();

            $input = [
                "cptid" => $req->cptid,
                "workflow_type" => $req->workflow_type,
            ];
            $rulesInput = [
                "cptid" => "nullable|integer|not_in:0",
                "workflow_type" => "required|integer|not_in:0",
            ];

            // validasi input
            $isValidInput = Validator::make($input, $rulesInput);
            if (!$isValidInput->passes()) {
                $apiResp = Responses::bad_input($isValidInput->messages()->first());
                return new Response($apiResp, $apiResp["meta"]["code"]);
            }

            if ($req->cptid) {
                $client = Clients::getClientById($req->cptid);
                if (count($client) < 1) {
                    $apiResp = Responses::not_found("client not found");
                    return new Response($apiResp, $apiResp["meta"]["code"]);
                }
            }

            // $zones = Zone::getActiveZones($req->cptid, Zone::ZONE_TYPE_WAREHOUSE, $req->workflow_type);
            $zones = Zone::getActiveZones(
                $req->cptid,
                [Zone::ZONE_TYPE_WAREHOUSE, Zone::ZONE_TYPE_AREA],
                $req->workflow_type
            );
            if (count($zones) < 1) {
                $apiResp = Responses::not_found("no available zones for client " . $client[0]->c_name);
                return new Response($apiResp, $apiResp["meta"]["code"]);
            }

            foreach ($zones as $key => $val) {
                unset($zones[$key]->boundary_points);
            }

            $apiResp = Responses::success("success list client zone");
            $apiResp["data"] = $zones;
            return new Response($apiResp, $apiResp["meta"]["code"]);
        } catch (\Exception $e) {
            $apiResp = Responses::error($e->getMessage());
            return new Response($apiResp, $apiResp["meta"]["code"]);
        }
    }

    public function api_list_checkpoints(Request $req)
    {
        try {
            $now = time();

            $input = [
                "cptid" => $req->cptid,
                // 'type' => $req->type,
                // 'workflow_type' => $req->workflow_type,
            ];
            $rulesInput = [
                "cptid" => "nullable|integer|not_in:0",
                // 'type' => 'required|integer|not_in:0',
                // 'workflow_type' => 'required|integer|not_in:0',
            ];

            // validasi input
            $isValidInput = Validator::make($input, $rulesInput);
            if (!$isValidInput->passes()) {
                $apiResp = Responses::bad_input($isValidInput->messages()->first());
                return new Response($apiResp, $apiResp["meta"]["code"]);
            }

            $zones = Zone::listZones($req->auth, [
                "is_active" => Zone::STATUS_ACTIVE,
            ]);
            if (count($zones) < 1) {
                $apiResp = Responses::not_found("no available checkpoints");
                return new Response($apiResp, $apiResp["meta"]["code"]);
            }

            foreach ($zones as $key => $val) {
                unset($zones[$key]->boundary_points);
            }

            $apiResp = Responses::success("success list checkpoints");
            $apiResp["data"] = $zones;
            return new Response($apiResp, $apiResp["meta"]["code"]);
        } catch (\Exception $e) {
            $apiResp = Responses::error($e->getMessage());
            return new Response($apiResp, $apiResp["meta"]["code"]);
        }
    }

    public function api_user_checker_change_zone(Request $req)
    {
        try {
            $now = time();

            $input = [
                "ord_code" => $req->ord_code,
                "zid" => $req->zid,
                "zone_name" => $req->zone_name,
                "zone_client" => $req->zone_client,
                "zone_type" => $req->zone_type,
                "workflow_zone_type" => $req->workflow_zone_type,
                "shiptocode" => $req->shiptocode,
                "prid" => $req->prid,
                "ktid" => $req->ktid,
                "kcid" => $req->kcid,
                "klid" => $req->klid,
                "fulladdress" => $req->fulladdress,
                "status" => $req->status,
                "boundary_hex_color" => $req->boundary_hex_color,
                "boundary_type" => $req->boundary_type,
                "boundary_latlngs" => $req->boundary_latlngs,
                "boundary_bounds" => $req->boundary_bounds,
                "boundary_radius" => $req->boundary_radius,
                "boundary_diameter" => $req->boundary_diameter,
                "boundary_area" => $req->boundary_area, // square meter
                "boundary_ha" => $req->boundary_ha, // hectare
            ];
            $rulesInput = [
                "ord_code" => "required|string|max:12",
                "zid" => "required|integer|not_in:0",
                "zone_name" => "required|string|max:255",
                "zone_client" => "nullable|integer|not_in:0",
                "zone_type" => "required|integer|not_in:0",
                "workflow_zone_type" => "required|integer|not_in:0",
                "shiptocode" => "required|string|min:5|max:6",
                "prid" => "required|numeric",
                "ktid" => "required|numeric",
                "kcid" => "required|numeric",
                "klid" => "required|numeric",
                "fulladdress" => "required|string|min:55",
                "status" => "required|integer|not_in:0",
                "boundary_hex_color" => "required|string|min:7|max:7",
                "boundary_type" => "required|string|max:25",
                "boundary_latlngs" => "required|array",
                "boundary_latlngs.*.lat" => "required",
                "boundary_latlngs.*.lng" => "required",
                "boundary_bounds" => "nullable|array",
                "boundary_radius" => "nullable|numeric",
                "boundary_diameter" => "nullable|numeric",
                "boundary_area" => "nullable|numeric",
                "boundary_ha" => "nullable|numeric",
            ];

            // validasi input
            $isValidInput = Validator::make($input, $rulesInput);
            if (!$isValidInput->passes()) {
                $apiResp = Responses::bad_input($isValidInput->messages()->first());
                return new Response($apiResp, $apiResp["meta"]["code"]);
            }

            $zone = Zone::showZoneById($req->zid);
            if (count($zone) < 1) {
                $apiResp = Responses::not_found("zone not found");
                return new Response($apiResp, $apiResp["meta"]["code"]);
            }

            $uniqName = Zone::getZoneByName($req->zone_name);
            if (count($uniqName) > 0) {
                $notSameUser = 1;
                foreach ($uniqName as $key => $row) {
                    if ($row->id == $req->zid) {
                        $notSameUser = 0;
                    }
                }
                if ($notSameUser) {
                    $apiResp = Responses::bad_request("zone name has been used");
                    return new Response($apiResp, $apiResp["meta"]["code"]);
                }
            }

            $orders = Orders::showOrder([
                "code" => $req->ord_code,
                // 'get_stts_checker' => 1,
                // 'get_prefer_type_truck' => 1,
                // 'get_checker_data' => 1,
                // 'get_client_pt' => 1,
                // 'get_accidents' => 1,
                "couple_pck_drop" => 1,
                "get_pic_zone" => 1,
                // 'get_user_aprv_pck' => 1,
                // 'get_user_aprv_pck' => 1,
                "group_by" => "ord.id",
            ]);
            if (count($orders) < 1) {
                $apiResp = Responses::not_found("order not found");
                return new Response($apiResp, $apiResp["meta"]["code"]);
            }
            $order = $orders[0];

            $user = Users::getUserById($req->auth->uid);

            DB::beginTransaction();

            $updtZone = [
                "name" => $req->zone_name,
                "type" => $req->zone_type,
                "workflow_type" => $req->workflow_zone_type,
                "shiptocode" => $req->shiptocode,
                "prid" => $req->prid,
                "ktid" => $req->ktid,
                "kcid" => $req->kcid,
                "klid" => $req->klid,
                "fulladdress" => $req->fulladdress,
                "boundary_type" => $req->boundary_type,
                "boundary_hex_color" => strtoupper($req->boundary_hex_color),
                "boundary_latlngs" => json_encode($req->boundary_latlngs),
                "boundary_bounds" => $req->boundary_bounds ? json_encode($req->boundary_bounds) : null, // $req->boundary_bounds ?? null,
                "boundary_radius" => $req->boundary_radius ?? 0,
                "boundary_diameter" => $req->boundary_diameter ?? 0,
                "boundary_area" => $req->boundary_area ?? 0,
                "boundary_ha" => $req->boundary_ha ?? 0,
                "status" => $req->status,
                "client_group_id" => $req->zone_client ?? ($user[0]->client_group_id ?? null),
                "updt" => $now,
                "updt_by" => $req->auth->uid,
            ];

            // $updtZone['boundary_points'] = DB::raw("ST_GeomFromText('POINT($req->lng $req->lat)')");
            $updtZone["boundary_points"] = "ST_GeomFromText('MULTIPOINT(";

            foreach ($req->boundary_latlngs as $key => $val) {
                $updtZone["boundary_points"] .= $val["lng"] . " " . $val["lat"] . ", ";
            }
            $updtZone["boundary_points"] = substr($updtZone["boundary_points"], 0, -2); // remove 2 last character
            $updtZone["boundary_points"] .= ")')";
            $updtZone["boundary_points"] = DB::raw($updtZone["boundary_points"]);

            Zone::updateZone($req->zid, $updtZone);

            /**
             * UPDATE ABOUT ZONE DROP N TRANSACTIONS
             */

            $drops = Zone::getZoneById($req->zid, ["region_name" => 1]);
            if (count($drops) < 1) {
                $apiResp = Responses::not_found("Lokasi pengantaran tidak ditemukan");
                return new Response($apiResp, $apiResp["meta"]["code"]);
            }
            if (empty($drops[0]->boundary_points)) {
                $apiResp = Responses::bad_request("Lokasi pengantaran tidak valid");
                return new Response($apiResp, $apiResp["meta"]["code"]);
            }

            foreach ($drops as $iDrop => $drop) {
                if ($drop->prid == 0 || $drop->ktid == 0 || $drop->kcid == 0 || $drop->klid == 0) {
                    $apiResp = Responses::bad_request(
                        "Zonasi wilayah(provinsi, kecamatan, ...) lokasi pengantaran " .
                            $drop->name .
                            " belum lengkap"
                    );
                    return new Response($apiResp, $apiResp["meta"]["code"]);
                }
                $drops[$iDrop]->inpt_pic_name = $order->drop_pic_name;
                $drops[$iDrop]->inpt_pic_phone_code = 62;
                $drops[$iDrop]->inpt_pic_phone_val = (int) $order->drop_pic_phone_val;
                $drops[$iDrop]->inpt_pic_mail = null;

                $updtDrop = [
                    "ord_id" => $order->ord_id,
                    "ord_code" => $order->ord_code,
                    // 'stts_drop' => OrdersDrops::STTS_WAIT,
                    "drop_id" => $drop->id,
                    "drop_name" => $drop->name,
                    "drop_desc" => $drop->desc,
                    "drop_type" => $drop->type,
                    "drop_workflow" => $drop->workflow_type,
                    "drop_shiptocode" => $drop->shiptocode,
                    "drop_prid" => $drop->prid,
                    "drop_ktid" => $drop->ktid,
                    "drop_kcid" => $drop->kcid,
                    "drop_klid" => $drop->klid,
                    "drop_addr" => $drop->fulladdress,
                    "drop_cgroup_id" => $drop->client_group_id,
                    "drop_cdiv_id" => $drop->client_div_id,
                    "drop_cgp_id" => $drop->client_gp_id,
                    "drop_hex_color" => $drop->boundary_hex_color,
                    "drop_shape" => $drop->boundary_type,
                    "drop_radius" => $drop->boundary_radius,
                    "drop_diameter" => $drop->boundary_diameter,
                    "drop_area" => $drop->boundary_area,
                    "drop_ha" => $drop->boundary_ha,
                    "drop_bounds" => $drop->boundary_bounds,
                    "drop_latlngs" => $drop->boundary_latlngs,
                    "drop_points" => $drop->boundary_points,
                    "pic_name" => $drop->inpt_pic_name,
                    "pic_phone_code" => $drop->inpt_pic_phone_code,
                    "pic_phone_val" => $drop->inpt_pic_phone_val,
                    "pic_mail" => $drop->inpt_pic_mail,
                ];
                OrdersDrops::updtByOrdId($order->ord_id, $updtDrop);

                // $main_item_dec = "Pengantaran Logistik<br>" . ucwords(strtolower($pckPoints[0]->ktid_name)) . " - " . ucwords(strtolower($dropPoints[0]->ktid_name)) . "<br>" . ucwords(strtolower($dropPoints[0]->name)) . ", " . ucwords(strtolower($dropPoints[0]->prid_name)) . " - " . $dropPoints[0]->shiptocode . "<br>" . strftime('%d %m %Y', $insPck['set_pck_at']) . "<br>" . $req->note_tonase;
                $ktid_name = ucwords(strtolower($drop->ktid_name));
                $drop_name = ucwords(strtolower($drop->name));
                $prid_name = ucwords(strtolower($drop->prid_name));
                $shiptocode = $drop->shiptocode;
            }

            $a_items = OrdersAItems::showAItem([
                "ord_id" => $order->ord_id,
                "a_item_type" => OrdersAItems::A_TYPE_PRIMARY,
            ]);
            foreach ($a_items as $a_item) {
                // splitter
                $desc_br = explode("<br>", $a_item->desc);
                $nol = $desc_br[0]; // (string) Pengantaran Logistik
                $satu = explode("-", $desc_br[1]); // (array) pickup->ktid_name - drop->ktid_name
                $dua_0 = explode(",", $desc_br[2]); // (array) drop->name, drop->prid_name - drop->shiptocode
                $dua_1 = explode("-", $dua_0[1]); // (array) drop->prid_name - drop->shiptocode
                $tiga = $desc_br[3]; // (string) DD MM YYYY
                $empat = $desc_br[4]; // (string) $req->note_tonase

                // update string
                $satu[1] = " " . $ktid_name;
                $dua_0[0] = $drop_name;
                $dua_1[0] = " " . $prid_name . " ";
                $dua_1[1] = " " . $shiptocode;

                // concatination
                $dua_1 = implode("-", $dua_1);
                $dua_0[1] = $dua_1;
                $dua_0 = implode(",", $dua_0);
                $satu = implode("-", $satu);
                // concatination 2
                $desc_br[0] = $nol;
                $desc_br[1] = $satu;
                $desc_br[2] = $dua_0;
                $desc_br[3] = $tiga;
                $desc_br[4] = $empat;
                $main_item_desc = implode("<br>", $desc_br);

                OrdersAItems::updt($a_item->ord_a_item_id, [
                    "desc" => $main_item_desc,
                ]);
            }

            DB::commit();

            $apiResp = Responses::success("success update zone");
            return new Response($apiResp, $apiResp["meta"]["code"]);
        } catch (\Exception $e) {
            DB::rollBack();
            $apiResp = Responses::error($e->getMessage());
            return new Response($apiResp, $apiResp["meta"]["code"]);
        }
    }

    public function api_user_checker_change_zone_by_zid(Request $req)
    {
        try {
            $now = time();

            $input = [
                "ord_id" => $req->ord_id,
                "ord_code" => $req->ord_code,
                "ord_drop_id" => $req->ord_drop_id,
                "drop_zid" => $req->drop_zid,
            ];
            $rulesInput = [
                "ord_id" => "required|integer|not_in:0",
                "ord_code" => "required|string|max:12",
                "ord_drop_id" => "required|integer|not_in:0",
                "drop_zid" => "required|integer|not_in:0",
            ];

            // validasi input
            $isValidInput = Validator::make($input, $rulesInput);
            if (!$isValidInput->passes()) {
                $apiResp = Responses::bad_input($isValidInput->messages()->first());
                return new Response($apiResp, $apiResp["meta"]["code"]);
            }

            $zone = Zone::showZoneById($req->drop_zid);
            if (count($zone) < 1) {
                $apiResp = Responses::not_found("zone not found");
                return new Response($apiResp, $apiResp["meta"]["code"]);
            }

            $orders = Orders::showOrder([
                "code" => $req->ord_code,
                // 'get_stts_checker' => 1,
                // 'get_prefer_type_truck' => 1,
                // 'get_checker_data' => 1,
                // 'get_client_pt' => 1,
                // 'get_accidents' => 1,
                "couple_pck_drop" => 1,
                "get_pic_zone" => 1,
                // 'get_user_aprv_pck' => 1,
                // 'get_user_aprv_pck' => 1,
                "group_by" => "ord.id",
            ]);
            if (count($orders) < 1) {
                $apiResp = Responses::not_found("order not found");
                return new Response($apiResp, $apiResp["meta"]["code"]);
            }
            $order = $orders[0];

            $user = Users::getUserById($req->auth->uid);

            DB::beginTransaction();

            /**
             * UPDATE ABOUT ZONE DROP N TRANSACTIONS
             */

            $drops = Zone::getZoneById($req->drop_zid, ["region_name" => 1]);
            if (count($drops) < 1) {
                $apiResp = Responses::not_found("Lokasi pengantaran tidak ditemukan");
                return new Response($apiResp, $apiResp["meta"]["code"]);
            }
            if (empty($drops[0]->boundary_points)) {
                $apiResp = Responses::bad_request("Lokasi pengantaran tidak valid");
                return new Response($apiResp, $apiResp["meta"]["code"]);
            }

            foreach ($drops as $iDrop => $drop) {
                if ($drop->prid == 0 || $drop->ktid == 0 || $drop->kcid == 0 || $drop->klid == 0) {
                    $apiResp = Responses::bad_request(
                        "Zonasi wilayah(provinsi, kecamatan, ...) lokasi pengantaran " .
                            $drop->name .
                            " belum lengkap"
                    );
                    return new Response($apiResp, $apiResp["meta"]["code"]);
                }
                $drops[$iDrop]->inpt_pic_name = $order->drop_pic_name;
                $drops[$iDrop]->inpt_pic_phone_code = 62;
                $drops[$iDrop]->inpt_pic_phone_val = (int) $order->drop_pic_phone_val;
                $drops[$iDrop]->inpt_pic_mail = null;

                $updtDrop = [
                    "ord_id" => $order->ord_id,
                    "ord_code" => $order->ord_code,
                    // 'stts_drop' => OrdersDrops::STTS_WAIT,
                    "drop_id" => $drop->id,
                    "drop_name" => $drop->name,
                    "drop_desc" => $drop->desc,
                    "drop_type" => $drop->type,
                    "drop_workflow" => $drop->workflow_type,
                    "drop_shiptocode" => $drop->shiptocode,
                    "drop_prid" => $drop->prid,
                    "drop_ktid" => $drop->ktid,
                    "drop_kcid" => $drop->kcid,
                    "drop_klid" => $drop->klid,
                    "drop_addr" => $drop->fulladdress,
                    "drop_cgroup_id" => $drop->client_group_id,
                    "drop_cdiv_id" => $drop->client_div_id,
                    "drop_cgp_id" => $drop->client_gp_id,
                    "drop_hex_color" => $drop->boundary_hex_color,
                    "drop_shape" => $drop->boundary_type,
                    "drop_radius" => $drop->boundary_radius,
                    "drop_diameter" => $drop->boundary_diameter,
                    "drop_area" => $drop->boundary_area,
                    "drop_ha" => $drop->boundary_ha,
                    "drop_bounds" => $drop->boundary_bounds,
                    "drop_latlngs" => $drop->boundary_latlngs,
                    "drop_points" => $drop->boundary_points,
                    "pic_name" => $drop->inpt_pic_name,
                    "pic_phone_code" => $drop->inpt_pic_phone_code,
                    "pic_phone_val" => $drop->inpt_pic_phone_val,
                    "pic_mail" => $drop->inpt_pic_mail,
                ];
                OrdersDrops::updt($order->ord_drop_id, $updtDrop);

                // $main_item_dec = "Pengantaran Logistik<br>" . ucwords(strtolower($pckPoints[0]->ktid_name)) . " - " . ucwords(strtolower($dropPoints[0]->ktid_name)) . "<br>" . ucwords(strtolower($dropPoints[0]->name)) . ", " . ucwords(strtolower($dropPoints[0]->prid_name)) . " - " . $dropPoints[0]->shiptocode . "<br>" . strftime('%d %m %Y', $insPck['set_pck_at']) . "<br>" . $req->note_tonase;
                $ktid_name = ucwords(strtolower($drop->ktid_name));
                $drop_name = ucwords(strtolower($drop->name));
                $prid_name = ucwords(strtolower($drop->prid_name));
                $shiptocode = $drop->shiptocode;
            }

            $a_items = OrdersAItems::showAItem([
                "ord_id" => $order->ord_id,
                "a_item_type" => OrdersAItems::A_TYPE_PRIMARY,
            ]);
            foreach ($a_items as $a_item) {
                // splitter
                $desc_br = explode("<br>", $a_item->desc);
                $nol = $desc_br[0]; // (string) Pengantaran Logistik
                $satu = explode("-", $desc_br[1]); // (array) pickup->ktid_name - drop->ktid_name
                $dua_0 = explode(",", $desc_br[2]); // (array) drop->name, drop->prid_name - drop->shiptocode
                $dua_1 = explode("-", $dua_0[1]); // (array) drop->prid_name - drop->shiptocode
                $tiga = $desc_br[3]; // (string) DD MM YYYY
                $empat = $desc_br[4]; // (string) $req->note_tonase

                // update string
                $satu[1] = " " . $ktid_name;
                $dua_0[0] = $drop_name;
                $dua_1[0] = " " . $prid_name . " ";
                $dua_1[1] = " " . $shiptocode;

                // concatination
                $dua_1 = implode("-", $dua_1);
                $dua_0[1] = $dua_1;
                $dua_0 = implode(",", $dua_0);
                $satu = implode("-", $satu);
                // concatination 2
                $desc_br[0] = $nol;
                $desc_br[1] = $satu;
                $desc_br[2] = $dua_0;
                $desc_br[3] = $tiga;
                $desc_br[4] = $empat;
                $main_item_desc = implode("<br>", $desc_br);

                OrdersAItems::updt($a_item->ord_a_item_id, [
                    "desc" => $main_item_desc,
                ]);
            }

            DB::commit();

            $apiResp = Responses::success("success update zone");
            return new Response($apiResp, $apiResp["meta"]["code"]);
        } catch (\Exception $e) {
            DB::rollBack();
            $apiResp = Responses::error($e->getMessage());
            return new Response($apiResp, $apiResp["meta"]["code"]);
        }
    }

    public function api_universal_list_zones(Request $req)
    {
        try {
            $now = time();
            $input = [];
            $rulesInput = [];

            // validasi input
            // $isValidInput = Validator::make($input, $rulesInput);
            // if (!$isValidInput->passes()) {
            // 	$apiResp = Responses::bad_input($isValidInput->messages()->first());
            // 	return new Response($apiResp, $apiResp['meta']['code']);
            // }

            $filter = [];
            if ($req->cptid) {
                $filter["company"] = $req->cptid;
            }
            if ($req->status) {
                $filter["is_active"] = $req->status;
            }

            if ($req->auth->role === Users::ROLE_SPECIAL_TRACKING) {
                // $filter['vid'] = 0;
                $filter["company"] = $req->auth->client_group_id;
            }

            $list = Zone::listZones($req->auth, $filter);

            foreach ($list as $key => $row) {
                $list[$key]->DT_RowIndex = $key + 1;
                $list[$key]->action = "-";
                unset($list[$key]->boundary_points);
            }

            $apiResp = Responses::success("success list zones");
            $apiResp["data"] = $list;
            $apiResp["count"] = count($list);
            return new Response($apiResp, $apiResp["meta"]["code"]);
        } catch (\Exception $e) {
            $apiResp = Responses::error($e->getMessage());
            return new Response($apiResp, $apiResp["meta"]["code"]);
        }
    }
}
