<?php

namespace App\Services;

use Exception;
use Illuminate\Database\Eloquent\Builder;

class GridBuilder
{
    /** @var GridBasic */
    private $grid;

    /** @return  GridBuilder */
    public static function builder()
    {
        $builder = new GridBuilder();
        $builder->grid = new GridBasic();
        $builder->grid->columns = [];
        $builder->grid->data = [];
        $builder->grid->parameters = [];
        $builder->grid->label_no_records = 'No se encontraron registros';
        $builder->grid->ajaxGrid = false;
        return $builder;
    }

    public function enableAjaxGrid(){
        $this->grid->ajaxGrid = true;
        return $this;
    }
    
     /** @return  GridBuilder */
     public function addColumn($params){
        $column = new GridColumnBasic();
        $column->name = $params['name'];
        $column->title = $params['title'] ?? $params['name'];
        $column->sort = boolval($params['sort'] ?? false);
        $column->filter = $params['filter'] ?? false;
        $column->filter_values = $params['filter_values'] ?? null;
        $column->html_decorator = $params['html_decorator'] ?? null;
        $column->filter_decorator = $params['filter_decorator'] ?? null;
        $column->encode = boolval($params['encode'] ?? true);
        $column->style = $params['style'] ?? null;
        $column->filter_field_type = $params['filter_field_type'] ?? null;
        $column->position = count($this->grid->columns);
        $this->grid->columns[$column->name] = $column;
        return $this;
    }

     /** @return  GridBuilder */
     public function htmlid($htmlid){
        $this->grid->htmlid = $htmlid;
        return $this;
     }

    /** @return  GridBuilder */
    public function data(Builder $data){
        $this->grid->data = $data;
        return $this;
    }

    /** @return  GridBuilder */
    public function recordsPerPage($recordsPerPage)
    {
        if( intval($recordsPerPage) ){
            $this->grid->recordsPerPage = intval($recordsPerPage);
        } else {
            throw new Exception("GridBuilder: invalid recordsPerPage[$recordsPerPage]");
        }
        return $this;
    }

    /** @return  GridBuilder */
    public function parameters($parameters){
        if( is_array($parameters) ){
            $this->grid->parameters = $parameters;
        } else {
            throw new Exception("GridBuilder: invalid parameters[$parameters]");
        }
        return $this;
    }
    

    /** @return  GridBuilder */
    public function label_no_records($label_no_records){
        if( is_string($label_no_records) ) {
            $this->grid->label_no_records = $label_no_records;
        } else {
            throw new Exception("GridBuilder: invalid label_no_records[$label_no_records]");
        }
        
        return $this;
    }

    /** @return  GridBuilder */
    public function defaultSort($default_sort_field_name, $default_sort_order){
        $this->grid->sort_field = $default_sort_field_name;
        $this->grid->sort_order = $default_sort_order;
        return $this;
    }

    /** @return  GridBuilder */
    public function rowStyle($row_style){
        $this->grid->row_style = $row_style;
        return $this;
    }
    
    
    /** @return  GridBasic */
    public function build()
    {
        $this->grid->sort_field = request('sf', $this->getDefaultSortFieldPosition());
        $this->grid->sort_order = request('so', $this->grid->sort_order ?? 'asc');
        $filters    = request('filter', []);

        
        
        
        $counter = 0;
        /** @var GridColumnBasic */
        foreach($this->grid->columns as $column){
            
            //add sorting
            if( $column->sort && $this->grid->sort_field == $counter){
                $this->grid->data->orderBy($column->name, $this->grid->sort_order);
            }

            //add filtering
            
            if( $filters[$counter] ?? false ){
                
                $column_name = is_string($column->filter) ? $column->filter : $this->resolveSqlAliasColumn($column->name);
                $column_value = $filters[$counter];

                //invalid date format
                if( $column->filter_field_type == 'date' && !strtotime($column_value) ){
                    $column_value = '';
                }

                if( $column->filter_decorator ){
                    ($column->filter_decorator)($this->grid, $column_value);
                } else if( $column->filter_values ) {
                    $this->grid->data->where($column_name, $column_value);
                } else {
                    $this->grid->data->where($column_name, 'LIKE', '%' . $column_value . '%');
                }
                //$this->grid->data->getQuery()->columns;
            }

            $counter++;
        }

        //dd($this->grid->data->toSql());
        $this->grid->data = $this->grid->data
            ->paginate( $this->grid->recordsPerPage ?? 2000000000 )
            ->withPath(request()->url());
        
        return $this->grid;
    }

    protected function resolveSqlAliasColumn($column_alias){

        if( !is_array($this->grid->data->getQuery()->columns) ){
            return $column_alias;
        }
        
        $sqlColumns = [];
        foreach($this->grid->data->getQuery()->columns as $column){
            if( !is_string($column) ){
                continue;
            }
            
            $column = strtolower($column);
            $column = explode(' as ', $column);
            
            if( count($column) == 1 ){
                $sqlColumns[ trim($column[0]) ] = trim($column[0]);
            } else if( count($column) == 2 ){
                $sqlColumns[ trim($column[0]) ] = trim($column[0]);
                $sqlColumns[ trim($column[1]) ] = trim($column[0]);
            }
        }

        if( count($sqlColumns) == 0 ) {
            return $column_alias;
        }

        if( array_key_exists($column_alias, $sqlColumns) ){
            return $sqlColumns[ $column_alias ];
        } else {
            throw new Exception("GridBuilder:No se reconoce la columna [$column_alias]");
        }
    }

    protected function getDefaultSortFieldPosition(){
        $counter = 0;

        /** @var GridColumnBasic */
        foreach($this->grid->columns as $column){
            if( $this->grid->sort_field == $column->name ){
                return $counter;
            }
            $counter++;
        }

        return 0;
    }
}


Class GridBasic {
    public $htmlid;
    public $columns;
    public $data;
    public $label_no_records;
    public $recordsPerPage;
    public $parameters;
    public $sort_field;
    public $sort_order;
    public $row_style;
    public $ajaxGrid;
}

class GridColumnBasic {
    public $name;
    public $title;
    public $sort;
    public $filter;
    public $filter_values;
    public $filter_field_type;
    public $encode;
    public $style;
    public $html_decorator;
    public $filter_decorator;
    public $position;
}
