<?php

namespace App\Utilities;

use Illuminate\Support\Str;
use Carbon\Carbon;

use App\Models\ContentElement;
use App\Models\Page;
use App\Models\Blog;
use App\Models\Announcement;
use App\Models\Livestream;
use App\Models\Photo;
use App\Models\Course;

use App\Utilities\Paginate;

class SearchResult
{
    public $type;
    public $id;
    public $url;
    public $title;
    public $preview;
    public $rank;
    public $url_text;
    public $date;
    public $photo;

    public function __construct($type, $id, $url, $title, $preview, $rank, $url_text, $date = null, $photo = null)
    {
        $this->type = $type;
        $this->id = $id;
        $this->url = $url;
        $this->title = $title;
        $this->preview = $preview;
        $this->rank = $rank;
        $this->url_text = $url_text;
        $this->date = $date;
        $this->photo = $photo;
    }

    public function toArray()
    {
        return collect($this)->toArray();
    }

    public static function collectTerms($terms = null)
    {
        if (!$terms) {
            $terms = request('terms');
        }

        if (!is_array($terms)) {
            if (Str::length($terms) < 2 && !is_numeric($terms)) {
                return collect();
            }

            $terms = collect(explode(' ', $terms));
        }

        $terms = $terms->filter(function ($term) {
            return Str::length($term) > 2 || is_numeric($term);
        });

        return $terms;
    }

    public static function search($terms = null, $filters = null)
    {
        $terms = SearchResult::collectTerms($terms);

        if (is_array(request('filters'))) {
            $filters = collect(request('filters'))->filter()->keys();
        } else {
            if (!$filters) {
                $filters = collect();
            }
        }

        //$results = cache()->tags([cache_name('search')])->remember(cache_name('search').'-'.(auth()->check() ? auth()->user()->id : 'guest').'-'.Str::kebab(implode('-', $terms)), 600, function () use ($terms, $filters) {
        $results = collect([
            ContentElement::searchResults($terms, $filters),
        ]);

        if ($filters->count()) {
            if ($filters->contains('pages')) {
                $results->push(Page::searchResults($terms));
            }

            if ($filters->contains('livestreams')) {
                $results->push(Livestream::searchResults($terms));
            }

            if ($filters->contains('blogs')) {
                $results->push(Blog::searchResults($terms));
            }

            if ($filters->contains('announcements')) {
                $results->push(Announcement::searchResults($terms));
            }

            if ($filters->contains('courses')) {
                $results->push(Course::searchResults($terms));
            }

            if ($filters->contains('photos')) {
                $results->push(Photo::searchResults($terms));
            }
        }

        return $results->flatten(1)
            ->groupBy(function ($result) {
                return $result->type.$result->id;
            })
            ->map(function ($results) {
                $result = $results->sortByDesc('rank')->first();

                $rank = $results->sum->rank;
                $months = $result->date->diffInMonths(now()) * 0.01;
                $result->rank = round(($rank - $months), 2);

                $result->photo = $results->map->photo->filter()->first();
                return $result;
            })
            ->flatten(1)
            ->sortByDesc(function ($result) {
                return $result->rank;
            })
            ->values();
    }

    public static function urlText($url_text)
    {
        $url_text = preg_replace('/\/(?=\w)/', ' > ', $url_text);
        $url_text = str_replace('/', '', $url_text);
        $url_text = str_replace('-', ' ', $url_text);
        $url_text = Str::title($url_text);
        return trim($url_text);
    }

    public static function truncatePreview($string, $terms)
    {
        $positions = collect();

        $string = trim(strip_tags(str_replace('<', ' <', $string)));

        $total_length = mb_strlen($string);

        if ($total_length < 1) {
            return ''; // there was no text so try the next content element for pageables
        }

        //dump('STRING');
        //dump($string);

        if (!is_array($terms) && is_string($terms)) {
            $terms = [$terms];
        }

        foreach ($terms as $term) {
            $offset = 0;
            while (($offset = mb_strpos(mb_strtolower($string), mb_strtolower($term), $offset)) !== false) {
                $positions[] = $offset;
                $offset = $offset + mb_strlen($term);
            }
        }

        if ($positions->count()) {
            $positions = $positions->sort()->values();
        } else {
            $positions[] = 1;
        }

        //dump('POSITIONS');
        //dump($positions);

        $segments = collect();
        $current_offeset = 0;

        foreach ($positions as $index => $position) {
            //dump('CURRENT: '.$current_offeset);
            $start = $position - 60;

            if ($start < 0) {
                $start = 0;
            }

            $end = $start + 120;

            // find the next space
            if ($end < $total_length) {
                $end = mb_strpos($string, ' ', $end - 1);
            }

            if ($end > $total_length) {
                $end = $total_length;
            }

            if ($index + 1 < $positions->count()) {
                if ($end < $positions[$index + 1]) {
                    //dump('ADD: '.$start.':'.$end);
                    $segments[$start] = $end;
                    $current_offeset = $end;
                } else {
                    //dump('NEXT');
                }
            } else {
                //dump('END: '.$start.':'.$end);
                $segments[$start] = $end;
            }
        }

        //dump('SEGMENTS');
        //dump($segments);

        $words = [];

        $last_character = 0;
        foreach ($segments as $start => $end) {
            $last_character = $end;

            $chunk = mb_substr($string, $start, $end - $start);


            /*
            if ($end == $segments->first()) {
                if (!Str::startsWith($chunk, '<p>')) {
                    $chunk = '<p> ... '.$chunk;
                }
            }

            if ($end == $segments->last()) {
                if (!Str::endsWith($chunk, '</p>')) {
                    $chunk = $chunk.' ... </p>';
                }
            }
             */

            $words[] = $chunk;
        }

        $implode = implode(' ... ', $words);

        if ($total_length > $last_character) {
            $implode = $implode.' ... ';
        }

        if (mb_strlen($implode) > 303) {
            $implode = mb_substr($implode, 0, mb_strpos($implode, ' ', 300)).' ... ';
        }

        return $implode;
    }
}
