<?php
namespace App\Libs\Services;

use App\Models\GenericBackoffice\WebsiteObject;
use App\Models\GenericBackoffice\Entry;
use App\Models\PageTab;
use App\Models\Block;
use Illuminate\Support\Facades\DB;
class SearchService
{
    public function search($q, $lang, $characters) {
        $escapedQuery = fulltext_search_term($q, false, false);

        $websiteObjectCollection = 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])
            ->get();
            $this->transformResult($websiteObjectCollection, $lang);
        $values = [];
        foreach ($websiteObjectCollection as $key => $langEntry) {
            $values[] = [
                'search'     => $this->string_range_match($langEntry->search_content, $characters, $q, '<||>'),
                'title'      => $langEntry->title,
                'url'        => $langEntry->lang_uri,
                'isExternal' => !empty($langEntry->isExternal) ? $langEntry->isExternal : false,
            ];
        }
        return $values;

    }

    private function transformResult($collection, $lang) {
        $pageTabsCollection = $collection->filter(function ($value) {
            return $value->content_type === 'pageTab';
        });
        $pageTabsCollection->load(['objectable' => function($query) {
            $query->full();
        }]);
        load_polymorphic_dependencies($pageTabsCollection, 'objectable', PageTab::class, ['block' => function($query) {
            $query->full()->select('*')->with(['entry' => function($query) {
                $query->full()->select('*');
            }]);
        }]);

        if (!$pageTabsCollection->isEmpty()) {
            $pageTabsCollection->each(function ($value, $key) {
                $value->objectable->block->each(function ($block, $key) use ($value) {
                    $block->entry->each(function ($entry, $key) use ($value) {
                        $value->title = $entry->title . ' - ' . $value->title;
                        $value->lang_uri = $entry->lang_uri . '#' . $value->lang_slug;
                        $value->isExternal = false;
                    });
                });
            });
        }
        $lists = [
            'firmware' => 'blockFirmwaresList',
            'project' => 'blockCommunityList',
            'schematic' => 'blockSchematicsList',
            'threeDModel' => 'blockThreeDModelsList',
            'api' => 'blockApisList',
        ];

        foreach ($lists as $contentType => $type) {
            $listsCollection = $collection->filter(function ($value) use ($contentType) {
                return $value->content_type === $contentType;
            });
            if ($listsCollection->isEmpty()) {
                continue;
            }
            $topEntry = DB::table('entries')
            ->select('entries_lang.title', 'website_objects_lang.lang_uri')
            ->join('entries_lang', 'entries.id', '=', 'entries_lang.entry_id')
            ->join('website_objects', function($join) {
                $join->on('entries.id', '=', 'website_objects.object_id')
                ->where('website_objects.object_type', Entry::class);
            })
            ->join('website_objects_lang', 'website_objects.website_object_id', '=', 'website_objects_lang.website_object_id')
            ->where('website_objects.status', 'published')
            ->where('website_objects_lang.wo_language_id', $lang)
            ->where('entries_lang.language_id', $lang)
            ->whereExists(function ($query) use ($type) {
                $query->select(DB::raw(1))
                ->from('entry_block')
                ->join('blocks', 'entry_block.block_id', '=', 'blocks.id')
                ->join('website_objects as blocksWebsiteObject', function($join) {
                    $join->on('blocks.id', '=', 'blocksWebsiteObject.object_id')
                    ->where('blocksWebsiteObject.object_type', Block::class);
                })
                ->whereRaw('entries.id = entry_block.entry_id')
                ->where('blocks.type', $type);
            })->first();
            $listsCollection->each(function ($value) use ($topEntry) {
                $value->title = $topEntry->title . ' - ' . $value->title;
                $value->lang_uri = $topEntry->lang_uri;
                $value->isExternal = false;
            });
        }
    }

    private function string_range_match($string, $characters = null, $word, $match = '') {
        $searchResults = array_filter(explode($match, $string));
        $stringToReturn = '';
        if (count($searchResults) > 0) {

            $searchKey = false;
            foreach ($searchResults as $key => $value) {
                if (empty($stringToReturn)) {
                    $stringToReturn = $searchResults[$key];
                }
                if (stripos($value, $word) !== FALSE) {
                    $word = substr($value, stripos($value, $word), strlen($word));
                    $searchKey = $key;
                }
            }
            if ($searchKey) {
                $stringToReturn = $searchResults[$searchKey];
                $characters = $characters - strlen($word);
                $halfCharacters = round($characters / 2, 0, PHP_ROUND_HALF_DOWN);
                $wordExploded = explode(strtolower($word), strtolower($stringToReturn));
                $beforeWord = $wordExploded[0];
                $afterWord = $wordExploded[1];

                if (strlen($stringToReturn) > $characters){
                    if (strlen($beforeWord) < $halfCharacters) {
                        $leftSide = substr($beforeWord, strlen($beforeWord));
                        $rightSide = substr($afterWord, 0, strripos(substr($afterWord, 0, $halfCharacters + ($halfCharacters - strlen($beforeWord))), ' ')) . '...';
                    } elseif (strlen($afterWord) < $halfCharacters) {
                        $leftSide = '...' . substr($beforeWord, 0, strripos(substr($beforeWord, 0, $halfCharacters + ($halfCharacters - strlen($afterWord))), ' ')) . ' ';
                        $rightSide = substr($afterWord, 0, strlen($afterWord));
                    } else {
                        $leftSide = '...' . ltrim(substr($beforeWord, strripos(substr($beforeWord, 0, strlen($beforeWord) - $halfCharacters), ' ')));
                        $rightSide = substr($afterWord, 0, strripos(substr($beforeWord, 0, $halfCharacters), ' ')) . '...';
                    }
                    $stringToReturn = $leftSide . '<b>' . $word . '</b>' . $rightSide;
                } else {
                    $stringToReturn = $beforeWord . '<b>' . $word . '</b>' . $afterWord;
                }
            }
        }
        return $stringToReturn;
    }
}
