<?php

namespace App\Filters;

use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Illuminate\Support\Arr;

class Filters
{
    /**
     * @var Request
     */
    protected $request;

    /**
     * The Eloquent builder.
     *
     * @var \Illuminate\Database\Eloquent\Builder
     */
    protected $builder;

    /**
     * Registered filters to operate upon.
     *
     * @var array
     */
    protected $filters = [];

    /**
     * Create a new ThreadFilters instance.
     *
     * @param Request $request
     */
    public function __construct()
    {
        $this->request = Request();
    }

    /**
     * Apply the filters.
     *
     * @param \Illuminate\Database\Eloquent\Builder $builder
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function apply($builder)
    {
        $this->builder = $builder;
        $fieldsSearchable = $this->getFieldsSearchable();
        $fields = $this->getFilters($fieldsSearchable);
        if (is_array($fields) && count($fields) && is_array($fieldsSearchable) && count($fieldsSearchable)) {
            foreach ($fields as $field => $value) {
                $method = Str::camel($field);
                if (method_exists($this, $method)) {
                    $this->$method($value);
                } elseif (isset($fieldsSearchable[$field])) {
                    $condition = $fieldsSearchable[$field];
                    $value = $condition == "like" ? "%{$value}%" : $value;
                    $relation = null;
                    if (stripos($field, '.')) {
                        $explode = explode('.', $field);
                        $field = array_pop($explode);
                        $relation = implode('.', $explode);
                    }
                    $modelTableName = $builder->getModel()->getTable();
                    $field = Str::snake($field);
                    if (!is_null($value)) {
                        if (!is_null($relation)) {
                            $builder->whereHas($relation, function ($query) use ($field, $condition, $value) {
                                $query->where($field, $condition, $value);
                            });
                        } else {
                            $builder->where($modelTableName . '.' . $field, $condition, $value);
                        }
                    }
                }
            }

            return $this->builder;
        }
    }

    /**
     * Fetch all relevant filters from the request.
     *
     * @return array
     */
    public function getFilters($fieldsSearchable)
    {
        if (!is_array($fieldsSearchable) || count($fieldsSearchable) == 0) {
            return [];
        }
        $keys = array_keys($fieldsSearchable);
        //$this->request->only()  会把user.nickname参数里包含"." 转换成数组
        //Arr::dot 方法使用「.」号将将多维数组转化为一维数组：

        return array_filter(Arr::dot($this->request->only($keys)), function ($value) {
            return !is_null($value) && $value != '';
        });
    }

    //获取model 可以查询的参数
    protected function getFieldsSearchable()
    {
        $model = $this->builder->getModel();
        if (!property_exists($model, 'fieldSearchable')) {
            return [];
        }
        $fieldSearchable = $model->fieldSearchable;
        $fields = [];
        foreach ($fieldSearchable as $field => $condition) {
            if (is_numeric($field)) {
                $field = $condition;
                $condition = "=";
            }
            $fields[$field] = $condition;
        }

        return $fields;
    }
}
