<?php

namespace App\Services\Filters\Applications;

use App\Models\Applications\Application;
use App\Models\Applications\ApplicationStatus;
use App\Models\Objects\FieldType;
use App\Models\User;
use App\Services\Filters\FiltersService;
use App\Transformers\Users\UserTransformer;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Date;
use Spatie\Fractal\Fractal;

class ApplicationFilters extends FiltersService {
    public function get(Collection $filters): array {
        $groups = [
            [
                'name' => 'common',
                'title' => 'Общие параметры',
                'fields' => $this->nativeFields($filters)
            ]
        ];
        $query = Application::query();
        $this->applyFilters($query, $filters);
        return ['groups' => ['data' => $groups], 'total' => $query->count()];
    }

    public function nativeFields(Collection $filters): array {
        return [
            [
                'name' => 'created_at',
                'title' => 'Дата формирования заявки',
                'type' => FieldType::DATE,
                'range' => $this->getDatesRange('created_at', $filters),
                'value' => $filters->get('created_at')
            ],
            [
                'name' => 'status',
                'title' => 'Статус',
                'type' => FieldType::RELATION,
                'represented' => $this->getStatuses($filters),
                'value' => $this->getRelationValue($filters->get('status'), ApplicationStatus::TITLES)
            ],
            [
                'name' => 'expert',
                'title' => 'Эксперт',
                'type' => FieldType::RELATION,
                'represented' => $this->getExperts($filters),
                'value' => ($val = $filters->get('expert')) ? fractal(User::byUuids($val)->get(), new UserTransformer()) : null
            ]
        ];
    }

    public function getDatesRange($prop, Collection $filters): array {
        $query = Application::query();
        $this->applyFilters($query, $filters->except($prop));
        return ['min' => ($v = $query->min($prop)) ? Date::create($v)->format('Y-m-d') : null, 'max' => ($v = $query->max($prop)) ? Date::create($v)->format('Y-m-d') : null];
    }


    public function getStatuses(Collection $filters): array {
        $query = Application::query()->whereNotNull('status')->distinct('status');
        $this->applyFilters($query, $filters->except('status'));
        $res = $query->get('status')->map(function($item) {return $item->status;})->all();
        return $this->getRelationItems(collect(ApplicationStatus::TITLES)->only($res)->all());
    }


    public function getExperts(Collection $filters): Fractal {
        return fractal(User::query()->whereHas('applicationConclusions.application', function($query) use($filters) {
            $this->applyFilters($query, $filters->except('expert'));
        })->orderBy('name')->get(), new UserTransformer());
    }


    public function applyFilters(Builder $query, Collection $filters) {
        $this->applyNativeFilters($query, $filters);
        $this->applyPermissionsFilters($query);
    }

    public function applyNativeFilters(Builder $query, Collection $filters) {
        $filters->each(function($value, $prop) use($query) {
            $this->applyNativeFilter($query, $prop, $value);
        });
    }

    public function applyNativeFilter(Builder $query, $prop, $value) {
        if ($value) {
            if ($prop === 'search') $this->applySearchFilter($query, $value, ['number', 'applicant', ['submitter' => ['name']], ['product' => ['name', 'purpose', 'normative', 'producer']]]);
            elseif ($prop === 'created_at') $this->applyDateFilter($query, 'created_at', $value);
            elseif ($prop === 'status') $query->whereIn('status', is_array($value) ? $value : [$value]);
            elseif ($prop === 'expert') $this->applyRelationFilter($query, 'conclusions.author', $value);
        }
    }

    public function applyPermissionsFilters(Builder $query) {
        $user = Auth::user();
        if (!$user->isExpert && !$user->isAdmin) $query->where(['submitter_id' => $user->id ?? null]);
    }

}
