<?php

namespace App\Services\Filters\Registries;

use App\Models\Dictionaries\Dictionary;
use App\Models\Objects\Field;
use App\Models\Objects\FieldType;
use App\Models\Objects\ObjectType;
use App\Models\Registries\Category;
use App\Models\Registries\Entry;
use App\Models\Registries\EntryState;
use App\Models\Registries\Registry;
use App\Services\Filters\FiltersService;
use App\Transformers\Dictionaries\DictionaryItemTransformer;
use App\Transformers\Objects\FieldTransformer;
use App\Transformers\Objects\ObjectTypeTransformer;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection;
use Spatie\Fractal\Fractal;

class EntryFilters extends FiltersService {
    public string $objectRelationName = 'entries';

    public function get(Collection $filters): array {
        $registry = Registry::byUuid($filters->get('registry'))->firstOrFail();
        $types = [];
        if ($v = ObjectType::byName($registry->options['operations'] ?? null)->first()) $types[] = $v->uuid;
        if ($v = ObjectType::byName($registry->options['properties'] ?? null)->first()) $types[] = $v->uuid;
        if ($types) $filters->put('types', $types);
        $groups = [
            [
                'name' => 'common',
                'title' => 'Общие параметры',
                'fields' => $this->nativeFields($filters)
            ]
        ];
        if ($types) $groups[] = ['name' => 'properties', 'title' => 'Дополнительные характеристики', 'fields' => $this->objectFields($filters)];
        //if ($v = $registry->options['properties'] ?? null) $groups[] = ['name' => 'properties', 'title' => 'Особые характеристики', 'fields' => $this->propertiesFields($v, $filters)];
        $query = Entry::query();
        $this->applyFilters($query, $filters->put('fake', 'zzz'));
        return ['groups' => ['data' => $groups], 'total' => $query->count()];
    }

    public function nativeFields(Collection $filters): array {
        return [
            [
                'name' => 'registry',
                'title' => 'Реестр',
                'type' => FieldType::STRING,
                'hidden' => true,
                'value' => $filters->get('registry')
            ],
            [
                'name' => 'types',
                'title' => 'Типы связанных объектов',
                'type' => FieldType::RELATION,
                'hidden' => true,
                'value' => $filters->get('types') ? fractal(ObjectType::whereIn('uuid', $filters->get('types'))->get(), new ObjectTypeTransformer()) : null
            ],
            [
                'name' => 'state',
                'title' => 'Статус',
                'type' => FieldType::RELATION,
                'represented' => $this->getRelationItems(EntryState::TITLES),
                'value' => $this->getRelationValue($filters->get('state'), EntryState::TITLES)
            ],
        ];
    }

    public function objectFields(Collection $filters): array {
        return fractal(Field::query()->whereHas('groups.objectType', function($query) use($filters) {
            $query->whereIn('uuid', $filters->get('types') ?? []);
        })->whereIn('type', [FieldType::RELATION, FieldType::DATE, FieldType::STRING])->get(), new FieldTransformer($filters->all(), $this))->toArray();
    }


    public function getListings(Collection $filters): Fractal {
        return fractal(Dictionary::byName('listings')->first()->items, new DictionaryItemTransformer());
    }


    public function applyFilters(Builder $query, Collection $filters) {
        $this->applyCategoryFilter($query, $filters);
        $this->applyNativeFilters($query, $filters);
        $this->applyObjectFilters($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, ['name', 'number']);
            elseif ($prop === 'registry') $this->applyRelationFilter($query, 'registry', $value);
            elseif ($prop === 'state') $query->byStates($value);
        }
    }


    public function applyObjectFilters(Builder $query, Collection $filters) {
        if ($filters->get('types') && !$this->isFiltersEmpty($filters, true)) $query->whereHas('objects', function($query) use($filters) {
            Field::applyFilters($query, $filters);
        });
    }



    public function applyCategoryFilter(Builder $query, Collection $filters) {
        if ($this->isFiltersEmpty($filters)) $query->where(['category_id' => Category::byUuid($filters->get('category'))->first()->id ?? 0]);
    }

    public function applyPermissionsFilters(Builder $query) {
    }



    public function isFiltersEmpty(Collection $filters, $exceptNative = false): bool {
        if ($exceptNative) $filters = $filters->filter(function($val, $prop) {
            return Field::byName($prop)->exists();
        });
        return $filters->except('registry', 'category', 'types', 'state')->filter(function($val) {
            return collect($val)->filter(function($val) {return $val;})->isNotEmpty();
        })->isEmpty();
    }


}
