<?php

namespace App\Libs\Services;

use App\Models\Document;
use App\Models\GenericBackoffice\WebsiteObject;
use App\Models\PressRelease;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\DB;
use Carbon\Carbon;

class SearchService
{
    public function search(string $q, string $contentType, string $lang, int $page = 1, int $perPage = 7, string $orderDir, string $orderBy, array $filters = []) {
        $escapedQuery = fulltext_search_term($q, false, false);

        $query = WebsiteObject::join('website_objects_search', 'website_objects_search.website_object_id', '=', 'website_objects.website_object_id')
            ->join('website_objects_lang', 'website_objects_lang.website_object_id', '=', 'website_objects.website_object_id')
            ->whereRaw("MATCH(website_objects_search.search_content) AGAINST (? IN BOOLEAN MODE)", [$escapedQuery])
            ->where('website_objects_search.language_id', $lang)
            ->where('website_objects_lang.wo_language_id', $lang)
            ->where('website_objects.status', 'published')
            ->select('website_objects.*', 'website_objects_search.id', 'website_objects_search.title', 'website_objects_search.search_content', 'website_objects_lang.lang_uri', 'website_objects_lang.lang_slug')
            ->orderByRaw("MATCH(website_objects_search.search_content) AGAINST (? IN BOOLEAN MODE) desc", [$escapedQuery]);

        $this->_excludePasswordProtectedPageContent($query);

        switch ($contentType) { //all, document, press
            case 'document':
                $query->where(function ($query) use ($filters) {
                    $query->where(function ($query) use ($filters) {
                        $query->where('website_objects.content_type', 'document');
                        $this->_addDocumentFilters($query, $filters);
                    });

                    if (empty($filters)) {
                        $query->orWhere('website_objects.content_type', 'fileCards');
                    }
                });

                break;

            case 'press':
                $query->where('website_objects.content_type', 'pressReleases');
                $this->_addPressFilters($query);

                break;
        }

        // if ($orderBy !== 'alphabetical' && $orderBy !== 'date') {
        //     $query->orderByRaw("MATCH(website_objects_search.search_content) AGAINST (? IN BOOLEAN MODE) desc", [$escapedQuery]);
        // }

        return $query->paginate($perPage, ['*'], 'page', $page);
    }

    protected function _excludePasswordProtectedPageContent(Builder $query): void
    {
        $query->where(function (Builder $query) {
            $query->where('website_objects.content_type', '!=', 'page')
                ->orWhereNotExists(function ($query) {
                    $query->select(DB::raw(1))
                        ->from('entries')
                        ->whereColumn('entries.id', 'website_objects.object_id')
                        ->whereNotNull('entries.password_protected')
                        ->where('entries.password_protected', '!=', '');
                });
        });

        $query->where(function (Builder $query) {
            $query->where('website_objects.content_type', '!=', 'fileCards')
                ->orWhereNotExists(function ($query) {
                    $query->select(DB::raw(1))
                        ->from('file_cards')
                        ->join('accordion_items', 'accordion_items.id', '=', 'file_cards.accordion_item_id')
                        ->join('entry_block', 'entry_block.block_id', '=', 'accordion_items.block_id')
                        ->join('entries', 'entries.id', '=', 'entry_block.entry_id')
                        ->whereColumn('file_cards.id', 'website_objects.object_id')
                        ->whereNotNull('entries.password_protected')
                        ->where('entries.password_protected', '!=', '');
                });
        });
    }

    protected function _addDocumentFilters(Builder $query, array $filters)
    {
        $query->whereHasMorph(
            'objectable',
            [Document::class],
            function (Builder $query) use ($filters) {
                $query->where(function ($query) {
                    $query->whereNull('publish_date')
                        ->orWhere('publish_date', '<=', Carbon::now('Europe/Brussels'));
                })->where(function ($query) {
                    $query->whereNull('expiration_date')
                        ->orWhere('expiration_date', '>', Carbon::now('Europe/Brussels'));
                });

                if (!empty($filters['subtopic'])) {
                    $topicTree = WebsiteObject::select('tree_ids')
                        ->where('object_id', $filters['subtopic'])
                        ->where('content_type', 'topics')
                        ->first();

                    if ($topicTree) {
                        $treeIds = $topicTree->tree_ids;
                        $query->whereHas('topics', function ($topicQuery) use ($treeIds) {
                            $topicQuery->whereIn('topics.id', $treeIds);
                        });
                    } else {
                        $query->whereHas('topics', function ($topicQuery) {
                            $topicQuery->where('topics.id', 0);
                        });
                    }
                } else if (!empty($filters['topic'])) {
                    $topicTree = WebsiteObject::select('tree_ids')
                        ->where('object_id', $filters['topic'])
                        ->where('content_type', 'topics')
                        ->first();

                    if ($topicTree) {
                        $treeIds = $topicTree->tree_ids;
                        $query->whereHas('topics', function ($topicQuery) use ($treeIds) {
                            $topicQuery->whereIn('topics.id', $treeIds);
                        });
                    } else {
                        $query->whereHas('topics', function ($topicQuery) {
                            $topicQuery->where('topics.id', 0);
                        });
                    }
                }

                if (!empty($filters['documentType'])) {
                    $query->where('document_type_id', $filters['documentType']);
                }

                if (!empty($filters['dateStart'])) {
                    $query->where(function($query) use ($filters) {
                        $query->whereDate('publish_date', '>=', $filters['dateStart'])
                            ->orWhereNull('publish_date');
                    });
                }

                if (!empty($filters['dateEnd'])) {
                    $query->where(function($query) use ($filters) {
                        $query->whereDate('publish_date', '<=', $filters['dateEnd'])
                            ->orWhereNull('publish_date');
                    });
                }
            }
        );
    }

    protected function _addPressFilters(Builder $query)
    {
        $query->whereHasMorph(
            'objectable',
            [PressRelease::class]
        );
    }

    public function searchAutoComplete(string $q, string $lang, int $perPage = 7) {
        $escapedQuery = fulltext_search_term($q, false, true);

        $query = WebsiteObject::join('website_objects_search', 'website_objects_search.website_object_id', '=', 'website_objects.website_object_id')
            ->join('website_objects_lang', 'website_objects_lang.website_object_id', '=', 'website_objects.website_object_id')
            ->whereRaw("MATCH(website_objects_search.search_content) AGAINST (? IN BOOLEAN MODE)", [$escapedQuery])
            ->where('website_objects_search.language_id', $lang)
            ->where('website_objects_lang.wo_language_id', $lang)
            ->where('website_objects.status', 'published')
            ->select('website_objects.*', 'website_objects_search.id', 'website_objects_search.title', 'website_objects_search.search_content', 'website_objects_lang.lang_uri', 'website_objects_lang.lang_slug')
            ->orderByRaw("MATCH(website_objects_search.search_content) AGAINST (? IN BOOLEAN MODE) desc", [$escapedQuery]);

            $query->where('website_objects.content_type', 'document');
            $this->_addDocumentFilters($query, []);

        return $query->limit($perPage)->get();
    }
}
