<?php

// error_reporting(E_ALL);

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;

if (! function_exists('process_datatable')) {
    /**
     * @param string $model_fullname full model class name. like: Spatie\Permission\Models\Role
     * @param array $fields List of allowed fields to be queried.
     * @param string $query query builder instance.
     * @param string $relation model's relation name (if has any relation). notic: this param is not table's name but it is the name of the method in model class which describes model foreign relations.
     */
    function processDataTable(Request $request, $model_fullname, array $fields=[], $query = '', string $relation = null)
    {
        if (!empty($model_fullname)) {
            $data = new $model_fullname();
        } elseif (!empty($query)) {
            $data = $query;
        } else {
            return [
                'status'  => 500,
                'message' => 'bad method invokation.'
            ];
        }

        if (!requestIsValid($request, $fields)) {
            return [
            'status' => 403,
            'message' => 'access to the requested resource is forbidden',
            ];
        }

        $columns = getColumns($request);

        $recordsTotal = $data->count();
        $recordsFiltered = $recordsTotal;

        $limit = $request->input('length');
        $start = $request->input('start');
        // $order = $columns[$request->input('order.0.column')]['name']['name'];


        // $dir = $request->input('order.0.dir');

        // create searchable fields array
        $search_fields = [];
        $is_searchable = false;

        foreach ($columns as $key => $value) {
            $name_array = $columns[$key]['name'];
            $rel = null;

            if ($request->input('columns.'.$key.'.searchable') == 'true') {
                $arr = array(
                    'value'    => $request->input('columns.'.$key.'.search.value'),
                    'type'     => $columns[$key]['name']['type'],
                );

                $field = $columns[$key]['name']['name'];

                $search_fields[$field] = $arr;
                $is_searchable = true;
            }
        }

        foreach ($search_fields as $field => $attributes) {
            if (isset($attributes['value'])) {
                $value = $attributes['value'];

                if ($attributes['type'] == 'text') {
                    $data = $data->where($field, 'LIKE', "%{$value}%");
                } elseif ($attributes['type'] == 'between') {
                    $date_values = explode('&', $value);
                    $date_values[0] .= " 00:00:00";
                    $date_values[1] .= " 23:59:59";
                    $data = $data->whereBetween($field, $date_values);
                } elseif ($attributes['type'] == 'between_time') {
                    $times = explode('_', $value);
                    $data = $data->where(function ($query) use ($times, $field) {
                        foreach ($times as $idx => $time_values) {
                            $time_values = explode('&', $time_values);
                            if ($idx == 0) {
                                $query = $query->whereBetween($field, $time_values);
                            } else {
                                $query = $query->orWhereBetween($field, $time_values);
                            }
                        }
                    });
                } elseif ($attributes['type'] == 'select') {
                    $data = $data->where($field, "{$value}");
                }

                // following types have been added for making finance table serverside.
                elseif ($attributes['type'] == 'is_null') {
                    $data = $value ? $data->whereNull($field) : $data->whereNotNull($field);
                }

                elseif ($attributes['type'] == 'date_between') {
                    $data = $data->whereBetween($field, explode('&', $value));
                }

                elseif ($attributes['type'] == 'multi_select') {
                    $data = $data->whereIn($field, explode(',', $value));
                }

                // useful when we want to get rows of a table where have related data in another table with specific condition.
                elseif ($attributes['type'] == 'relation.multi_select') {

                    if(!$relation){
                        return [
                            'status'  => 500,
                            'message' => 'bad method invokation.'
                        ];
                    }

                    $data = $data->whereHas($relation, function ($query) use ($field, $value) {
                        $query->whereIn($field, explode(',', $value));
                    });

                }
            }
        }

        foreach ($request->order as $key => $orderList) {

            $order = $columns[$orderList['column']]['name']['name'];
            $dir = $orderList['dir'];

            $data = $data->orderBy($order, $dir);
        }

        $recordsFiltered = $data->count();
        $data = $data->offset($start)
                           ->limit($limit)
                        //    ->orderBy($order, $dir)
                           ->get();

        return [
            'status' => 200,
            'draw' => $request->draw,
            'recordsTotal' => $recordsTotal,
            'recordsFiltered' => $recordsFiltered,
            'data' => $data
        ];
    }
}

if (! function_exists('getColumns')) {
    function getColumns(Request $request)
    {
        // $columns = [];
        // foreach ($request->columns as $col) {
        //     $columns[] = $col;
        // }

        return $request->columns;
    }
}

if (!function_exists('requestIsValid')) {
    function requestIsValid(Request $request, array $fields)
    {
        $columns = getColumns($request);

        // check column names
        foreach ($columns as $key => $value) {
            $colName = $columns[$key]['name']['name'];
            $colType = $columns[$key]['name']['type'];

            // do nothing if column is optional
            if (!in_array($colName, $fields) && $colType != 'option') {
                return false;
            }
        }

        // check order name
        $orderName = $columns[$request->input('order.0.column')]['name']['name'];
        if (!in_array($orderName, $fields)) {
            return false;
        }

        return true;
    }
}

if (!function_exists('makeSelectQuery')) {
    function makeSelectQuery(array $fields, array $aliases)
    {
        $select = '';
        for ($i = 0; $i < count($fields); $i++) {
            if ($aliases[$i]) {
                $select .= $fields[$i]. ' as '. $aliases[$i];
            } else {
                $select .= $fields[$i];
            }

            if ($i != count($fields) - 1) {
                $select .= ', ';
            }
        }

        return $select;
    }
}

if (!function_exists('setAxisTypeFa')) {
    function setAxisTypeFa(int $axis_type)
    {
        if ($axis_type == '1') {
            $axis_type_fa = 'آزادراه';
        } elseif ($axis_type == '2') {
            $axis_type_fa = 'بزرگراه';
        } elseif ($axis_type == '3') {
            $axis_type_fa = 'اصلی';
        } elseif ($axis_type == '4') {
            $axis_type_fa = 'فرعی';
        }

        return $axis_type_fa;
    }
}

if (!function_exists('get_way_id_from_nominatim')) {
    function get_way_id_from_nominatim($lat, $lng)
    {
        $url = "https://testmap.141.ir/nominatim/reverse?format=jsonv2&lat=".$lat."&lon=".$lng."&zoom=16&addressdetails=16";
        $arrContextOptions=array(
            "ssl"=>array(
                "verify_peer"=>false,
                "verify_peer_name"=>false,
            ),
        );

        $result = file_get_contents($url, false, stream_context_create($arrContextOptions));
        $result = json_decode($result);
        if (isset($result->osm_type)) {
            if ($result->osm_type == 'way') {
                return $result->osm_id;
            }
        }
        return 0;
    }
}

if (!function_exists('findCityFromGeoJson')) {
    function findCityFromGeoJson($lat, $lon)
    {
        $file_contents = file_get_contents(storage_path('cities-geojson.json'));

        $contents_array = json_decode($file_contents, true);
        $cities = $contents_array['features'];

        $city_idx = false;
        foreach ($cities as $idx => $city) {
            // dd($city['geometry']['coordinates'][0]);
            if (is_in_polygon($city['geometry']['coordinates'][0], $lat, $lon)) {
                $city_idx = $idx;
                break;
            }
        }

        // dd($cities[$city_idx]);

        return $city_idx ? $cities[$city_idx]['properties'] : false;
    }
}

if (!function_exists('is_in_polygon')) {
    function is_in_polygon($vertices, $latitude_y, $longitude_x)
    {
        $i = $j = $c = 0;
        $points_polygon = count($vertices);

        for ($i = 0, $j = $points_polygon - 1 ; $i < $points_polygon; $j = $i++) {
            if ((($vertices[$i][1] > $latitude_y != ($vertices[$j][1] > $latitude_y)) &&
            ($longitude_x < ($vertices[$j][0] - $vertices[$i][0]) * ($latitude_y - $vertices[$i][1]) / ($vertices[$j][1] - $vertices[$i][1]) + $vertices[$i][0]))) {
                $c = !$c;
            }
        }

        return $c;
    }
}
