<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;
use App\Models\Users;

class Zone extends Model
{
    const ZONE_TYPE_WAREHOUSE = 1;
    const ZONE_TYPE_AREA = 2;

    const ZONE_WORKFLOW_PICKUP = 1;
    const ZONE_WORKFLOW_DEST = 2; // alias drop zone
    const ZONE_WORKFLOW_PARKING = 3;
    const ZONE_WORKFLOW_SERVICE = 4;

    const ZONE_BOUNDARY_CIRCLE = "circle";
    const ZONE_BOUNDARY_POLYGON = "polygon";
    const ZONE_BOUNDARY_RECTANGLE = "rectangle";
    const ZONE_BOUNDARY_NAME_CIRCLE = "Circle";
    const ZONE_BOUNDARY_NAME_POLYGON = "Polygon";
    const ZONE_BOUNDARY_NAME_RECTANGLE = "Rectangle";

    const STATUS_ACTIVE = 1;
    const STATUS_INACTIVE = 2;

    const defaultSelectInsideZone = "
        z.id as zid,z.name,z.desc,z.type,zt.name as type_name,z.workflow_type,zw.name as workflow_type_name
        ,z.shiptocode,z.fulladdress,z.boundary_type,z.boundary_radius,z.boundary_latlngs,ST_AsText(boundary_points) as points
        ,z.client_group_id,c.c_name,c_mail,c.pic_name,c.pic_mail
    ";

    public static function listZones($auth, $filter = [])
    {
        $params = [];

        $query = "SELECT z.*";
        $query .= " ,c.c_name AS client_group_name";
        $query .= " ,zt.name AS type_name,zw.name AS workflow_type_name";
        $query .= " ,uc.first_name AS crt_name,up.first_name AS updt_name";
        $query .= " ,uc.role AS crt_role,up.role AS updt_role";
        $query .= " ,uc1.c_name AS crt_client_group_name,up1.c_name AS updt_client_group_name";
        $query .= " ,uc2.name AS crt_role_name,up2.name AS updt_role_name";
        $query .= " FROM t_zones AS z";
        $query .= " LEFT JOIN t_clients AS c ON z.client_group_id = c.id";
        $query .= " LEFT JOIN t_zones_types AS zt ON z.type = zt.id";
        $query .= " LEFT JOIN t_zones_workflows AS zw ON z.workflow_type = zw.id";
        $query .= " LEFT JOIN t_users AS uc ON z.crt_by = uc.id";
        $query .= " LEFT JOIN t_clients AS uc1 ON uc.client_group_id = uc1.id";
        $query .= " LEFT JOIN t_users AS up ON z.updt_by = up.id";
        $query .= " LEFT JOIN t_clients AS up1 ON uc.client_group_id = up1.id";
        $query .= " LEFT JOIN t_users_roles AS uc2 ON uc.role = uc2.id";
        $query .= " LEFT JOIN t_users_roles AS up2 ON up.role = up2.id";
        $query .= " WHERE z.dlt is null";

        if ($auth->role == Users::ROLE_CLIENT_ADMIN) {
            $query .= " AND z.client_group_id = " . $auth->client_group_id;
        }

        if ($auth->role == Users::ROLE_VENDOR) {
            $query .= " AND z.client_group_id = " . $auth->client_group_id;
        }

        if (isset($filter["is_active"])) {
            if ($filter["is_active"] == self::STATUS_ACTIVE) {
                $query .= " AND z.status = " . self::STATUS_ACTIVE;
            } elseif ($filter["is_active"] == self::STATUS_INACTIVE) {
                $query .= " AND z.status = " . self::STATUS_INACTIVE;
            }
        }

        if (isset($filter["company"])) {
            $query .= " AND c.id = ?";
            $params[] = $filter["company"];
        }

        if (isset($filter["workflow_type"])) {
            $query .= " AND z.workflow_type = ?";
            $params[] = $filter["workflow_type"];
        }
        if (isset($filter["type"])) {
            $query .= " AND z.type = ?";
            $params[] = $filter["type"];
        }

        return DB::select($query, $params);

        // return DB::select("SELECT z.*
        // ,c.c_name AS client_group_name
        // ,zt.name AS type_name,zw.name AS workflow_type_name
        // ,uc.role AS crt_role,up.role AS updt_role
        // ,uc1.c_name AS crt_client_group_name,up1.c_name AS updt_client_group_name
        // ,uc2.name AS crt_role_name,up2.name AS updt_role_name
        // FROM t_zones AS z
        // LEFT JOIN t_clients AS c ON z.client_group_id = c.id
        // LEFT JOIN t_zones_types AS zt ON z.type = zt.id
        // LEFT JOIN t_zones_workflows AS zw ON z.workflow_type = zw.id
        // LEFT JOIN t_users AS uc ON z.crt_by = uc.id
        // LEFT JOIN t_clients AS uc1 ON uc.client_group_id = uc1.id
        // LEFT JOIN t_users AS up ON z.updt_by = up.id
        // LEFT JOIN t_clients AS up1 ON uc.client_group_id = up1.id
        // LEFT JOIN t_users_roles AS uc2 ON uc.role = uc2.id
        // LEFT JOIN t_users_roles AS up2 ON up.role = up2.id
        // WHERE z.dlt is null
        // ;");
    }

    // public static function getActiveZones($client_group_id = 0, $type = 0, $workflow_type = 0)
    // {
    //     $where_client_group_id = "";
    //     if ($client_group_id != 0) {
    //         $where_client_group_id = " AND z.client_group_id = " . $client_group_id;
    //     }

    //     $where_type = "";
    //     if ($type != 0) {
    //         $where_type = " AND z.type = " . $type;
    //     }

    //     $where_workflow_type = "";
    //     if ($workflow_type != 0) {
    //         $where_workflow_type = " AND z.workflow_type = " . $workflow_type;
    //     }

    //     return DB::select(
    //         "SELECT
    //     z.*
    //     FROM t_zones as z WHERE z.dlt is null AND z.status = " .
    //             Zone::STATUS_ACTIVE .
    //             $where_client_group_id .
    //             $where_type .
    //             $where_workflow_type .
    //             " ;"
    //     );
    // }

    public static function getActiveZones($client_group_id = 0, $type = 0, $workflow_type = 0)
    {
        $where_client_group_id = "";
        if ($client_group_id != 0) {
            $where_client_group_id = " AND z.client_group_id = " . intval($client_group_id);
        }

        $where_type = "";
        if ($type != 0) {
            if (is_array($type)) {
                $type_list = implode(",", array_map("intval", $type));
                $where_type = " AND z.type IN (" . $type_list . ")";
            } else {
                $where_type = " AND z.type = " . intval($type);
            }
        }

        $where_workflow_type = "";
        if ($workflow_type != 0) {
            $where_workflow_type = " AND z.workflow_type = " . intval($workflow_type);
        }

        $sql =
            "SELECT
        z.*
        FROM t_zones as z
        WHERE z.dlt IS NULL
        AND z.status = " .
            Zone::STATUS_ACTIVE .
            $where_client_group_id .
            $where_type .
            $where_workflow_type .
            ";";

        return DB::select($sql);
    }

    public static function showZoneById($zid)
    {
        return DB::select(
            "SELECT z.*
		,c.c_name AS client_group_name
		,zt.name AS type_name,zw.name AS workflow_type_name
        ,(SELECT nmProvinsiKel FROM t_region WHERE kodeProv = z.prid LIMIT 1) as prid_name
        ,(SELECT nmKotamadyaKel FROM t_region WHERE kodeKab = z.ktid LIMIT 1) as ktid_name
        ,(SELECT nmKecamatanKel FROM t_region WHERE kodeKec = z.kcid LIMIT 1) as kcid_name
        ,(SELECT nmKelurahan FROM t_region WHERE kodeKel = z.klid LIMIT 1) as klid_name
		,uc.role AS crt_role,up.role AS updt_role
		,uc1.c_name AS crt_client_group_name,up1.c_name AS updt_client_group_name
		,uc2.name AS crt_role_name,up2.name AS updt_role_name
		FROM t_zones AS z
		LEFT JOIN t_clients AS c ON z.client_group_id = c.id
		LEFT JOIN t_zones_types AS zt ON z.type = zt.id
		LEFT JOIN t_zones_workflows AS zw ON z.workflow_type = zw.id
		LEFT JOIN t_users AS uc ON z.crt_by = uc.id
		LEFT JOIN t_clients AS uc1 ON uc.client_group_id = uc1.id
		LEFT JOIN t_users AS up ON z.updt_by = up.id
		LEFT JOIN t_clients AS up1 ON uc.client_group_id = up1.id
		LEFT JOIN t_users_roles AS uc2 ON uc.role = uc2.id
		LEFT JOIN t_users_roles AS up2 ON up.role = up2.id
		WHERE z.dlt is null
        AND z.id = ?
		LIMIT 1;",
            [$zid]
        );
    }

    public static function getZoneById($zid, $filter = [])
    {
        $select = "";

        if (isset($filter["region_name"])) {
            $select .= DB::raw(
                ",(SELECT nmProvinsiKel FROM t_region WHERE kodeProv = z.prid LIMIT 1) as prid_name ,(SELECT nmKotamadyaKel FROM t_region WHERE kodeKab = z.ktid LIMIT 1) as ktid_name"
            );
        }

        return DB::select("SELECT z.* $select FROM t_zones as z WHERE z.dlt is null AND z.id = ? LIMIT 1;", [
            $zid,
        ]);
    }

    public static function getZoneByIds($zids)
    {
        // dd($zids);
        $params = [];
        $where_in = "";
        foreach ($zids as $zid) {
            $where_in .= "?,";
            array_push($params, $zid);
        }
        if (strpos($where_in, ",") !== false) {
            $where_in = substr($where_in, 0, -1);
        }
        return DB::select(
            "SELECT z.*
        ,(SELECT nmProvinsiKel FROM t_region WHERE kodeProv = z.prid LIMIT 1) as prid_name
        ,(SELECT nmKotamadyaKel FROM t_region WHERE kodeKab = z.ktid LIMIT 1) as ktid_name
        -- ,(SELECT nmKecamatanKel FROM t_region WHERE kodeKec = z.kcid LIMIT 1) as kcid_name
        -- ,(SELECT nmKelurahan FROM t_region WHERE kodeKel = z.klid LIMIT 1) as klid_name
        FROM t_zones as z WHERE z.dlt is null AND z.id IN ($where_in);",
            $params
        );
    }

    public static function getZoneByName($name)
    {
        return DB::select("SELECT * FROM t_zones WHERE dlt is null AND name = ? LIMIT 2;", [$name]);
    }

    public static function insideZoneCircle($lat, $lng)
    {
        return DB::select(
            "SELECT
        " .
                Zone::defaultSelectInsideZone .
                "
        ,ST_Distance_Sphere( ST_GeomFromText('POINT($lng $lat)'), z.boundary_points) AS distance_meters
        ,MBRContains( boundary_points, ST_GeomFromText('POINT($lng $lat)') ) as is_contain
        ,MBRWithin( ST_GeomFromText('POINT($lng $lat)'), boundary_points ) as is_within
        FROM t_zones AS z
        INNER JOIN t_zones_types AS zt ON z.type = zt.id
        INNER JOIN t_zones_workflows AS zw ON z.workflow_type = zw.id
        LEFT JOIN t_clients AS c ON z.client_group_id = c.id
        WHERE z.dlt is null AND z.status = ? AND z.boundary_type IN (?)
        HAVING boundary_radius >= distance_meters
        ;",
            [Zone::STATUS_ACTIVE, Zone::ZONE_BOUNDARY_CIRCLE]
        );
    }

    public static function insideZoneShape($lat, $lng)
    {
        return DB::select(
            "SELECT
        " .
                Zone::defaultSelectInsideZone .
                "
        ,ST_Distance_Sphere( ST_GeomFromText('POINT($lng $lat)'), z.boundary_points) AS distance_meters
        ,MBRContains( boundary_points, ST_GeomFromText('POINT($lng $lat)') ) as is_contain
        ,MBRWithin( ST_GeomFromText('POINT($lng $lat)'), boundary_points ) as is_within
        FROM t_zones AS z
        INNER JOIN t_zones_types AS zt ON z.type = zt.id
        INNER JOIN t_zones_workflows AS zw ON z.workflow_type = zw.id
        LEFT JOIN t_clients AS c ON z.client_group_id = c.id
        WHERE z.dlt is null AND z.status = ? AND z.boundary_type IN (?,?)
        HAVING is_within = 1 AND is_contain = 1
        ;",
            [Zone::STATUS_ACTIVE, Zone::ZONE_BOUNDARY_POLYGON, Zone::ZONE_BOUNDARY_RECTANGLE]
        );
    }

    public static function insideOrdZoneCircle($lat, $lng, $filter = [])
    {
        $params = [Zone::STATUS_ACTIVE, Zone::ZONE_BOUNDARY_CIRCLE];
        $where = "";

        if (isset($filter["zid"])) {
            $where .= " AND z.id = ?";
            $params[] = $filter["zid"];
        }

        return DB::select(
            "SELECT
        " .
                Zone::defaultSelectInsideZone .
                "
        ,ST_Distance_Sphere( ST_GeomFromText('POINT($lng $lat)'), z.boundary_points) AS distance_meters
        ,MBRContains( boundary_points, ST_GeomFromText('POINT($lng $lat)') ) as is_contain
        ,MBRWithin( ST_GeomFromText('POINT($lng $lat)'), boundary_points ) as is_within
        FROM t_zones AS z
        INNER JOIN t_zones_types AS zt ON z.type = zt.id
        INNER JOIN t_zones_workflows AS zw ON z.workflow_type = zw.id
        LEFT JOIN t_clients AS c ON z.client_group_id = c.id
        WHERE z.dlt is null AND z.status = ? AND z.boundary_type IN (?)
        $where
        HAVING boundary_radius >= distance_meters
        ;",
            $params
        );
    }

    public static function insideOrdZoneShape($lat, $lng, $filter = [])
    {
        $params = [Zone::STATUS_ACTIVE, Zone::ZONE_BOUNDARY_POLYGON, Zone::ZONE_BOUNDARY_RECTANGLE];
        $where = "";

        if (isset($filter["zid"])) {
            $where .= " AND z.id = ?";
            $params[] = $filter["zid"];
        }

        return DB::select(
            "SELECT
        " .
                Zone::defaultSelectInsideZone .
                "
        ,ST_Distance_Sphere( ST_GeomFromText('POINT($lng $lat)'), z.boundary_points) AS distance_meters
        ,MBRContains( boundary_points, ST_GeomFromText('POINT($lng $lat)') ) as is_contain
        ,MBRWithin( ST_GeomFromText('POINT($lng $lat)'), boundary_points ) as is_within
        FROM t_zones AS z
        INNER JOIN t_zones_types AS zt ON z.type = zt.id
        INNER JOIN t_zones_workflows AS zw ON z.workflow_type = zw.id
        LEFT JOIN t_clients AS c ON z.client_group_id = c.id
        WHERE z.dlt is null AND z.status = ? AND z.boundary_type IN (?,?)
        $where
        HAVING is_within = 1 AND is_contain = 1
        ;",
            $params
        );
    }

    public static function addZone($data)
    {
        $zid = DB::table("t_zones")->insertGetId($data);
        return $zid;
    }

    public static function updateZone($zid, $data)
    {
        return DB::table("t_zones")
            ->where("id", $zid)
            ->update($data);
    }

    public static function updateZonesByGroupClientId($zid, $data)
    {
        return DB::table("t_zones")
            ->where("id", $zid)
            ->update($data);
    }

    public static function deleteZone($zid, $data)
    {
        return DB::table("t_zones")
            ->where("id", $zid)
            ->delete();
    }

    public static function arrStatus()
    {
        return [Zone::STATUS_ACTIVE, Zone::STATUS_INACTIVE];
    }

    public static function arrTypes()
    {
        return [Zone::ZONE_TYPE_WAREHOUSE];
    }

    public static function listTypes()
    {
        return DB::select("SELECT * FROM t_zones_types WHERE dlt is null;");
    }

    public static function arrWorkflows()
    {
        return [Zone::ZONE_WORKFLOW_PICKUP, Zone::ZONE_WORKFLOW_DEST, Zone::ZONE_WORKFLOW_PARKING];
    }

    public static function listWorkflows()
    {
        return DB::select("SELECT * FROM t_zones_workflows WHERE dlt is null;");
    }

    public static function arrBoundarys()
    {
        return [Zone::ZONE_BOUNDARY_CIRCLE, Zone::ZONE_BOUNDARY_POLYGON, Zone::ZONE_BOUNDARY_RECTANGLE];
    }

    public static function listBoundarys()
    {
        return [
            [
                "id" => Zone::ZONE_BOUNDARY_CIRCLE,
                "name" => Zone::ZONE_BOUNDARY_NAME_CIRCLE,
            ],
            [
                "id" => Zone::ZONE_BOUNDARY_POLYGON,
                "name" => Zone::ZONE_BOUNDARY_NAME_POLYGON,
            ],
            [
                "id" => Zone::ZONE_BOUNDARY_RECTANGLE,
                "name" => Zone::ZONE_BOUNDARY_NAME_RECTANGLE,
            ],
        ];
    }
}
