<?php

namespace Clevercherry\Backslash4\Traits;

use Clevercherry\Backslash4\Traits\observable;

trait searchModel
{
    use observable;

    /**
     * Build the cache file for the model
     */
    public function buildCache()
    {
        $cachePath = $this->checkDir();
        
        if(! is_file(storage_path('app/search_cache/' . $this->getTable()))) {
            touch(storage_path('app/search_cache/' . $this->getTable()));
        }

        $json = file_get_contents($cachePath);

        $results = json_decode($json);

        if(isset($results->{$this->id})) {
            $results->{$this->id} = $this;
            $results->{$this->id}->getRelationships();
        } else {
            $results = self::all()->keyBy('id');
            foreach($results AS $result) {
                $result->getRelationships($result);
            }
        }

        $json = json_encode($results);

        file_put_contents($cachePath, $json);
    }

    /**
     * Checks if the search cache directions exists, if not creates it
     * 
     * @return string - path to the models cache file
     */
    public function checkDir() : string
    {
        if(! is_dir(storage_path('app/search_cache'))) {
            mkdir(storage_path('app/search_cache'));
        }
        
        return storage_path('app/search_cache/' . $this->getTable());
    }

    /**
     * Query every model relationships and store results in the cache file
     * 
     * @return array
     */
    public function getRelationships()
    {
        foreach($this->relationships() AS $relationshipKey => $relationship) {
            $this->{$relationshipKey} = (new $relationship['model'])->where($relationship['primary_key'], $this->{$relationship['foreign_key']})->get();
        }

        if($this->hasBlocks()) {
            $this->blocks = (new \App\Models\Block)->where('model', $this->getTable())->where('modelId', $this->id)->get();
        }
    }

    /**
     * Returns results of a search query against a cache file
     * 
     * @param string $query = null - query to search against the cache
     * @param string $searchString - fully string to search against
     * @param int $limit - maximum number of results to be returned
     * 
     * @return array
     */
    public function getResults(?string $query = null, string $searchString, int $limit) : array
    {
        if(empty($query)) {
            $query = '*';
        }
        
        $results = [];
        $length = strlen($query);
        $array = json_decode($searchString, TRUE);

        if(is_array($array)) {
            foreach($array AS $key => $value) {
                $string = json_encode($value);
                $matchScore = (similar_text($string, $query) / $length);

                if($matchScore > 0.8) {
                    $results[$key] = $value;
                    $results[$key]['score'] = $matchScore;
                }
            }
        }
        
        $results = collect($results);
        $results = $results->sortByDesc('score')->slice(0, $limit)->toArray();

        return $results;
    }

    /**
     * Run a search against the models cache file
     * 
     * @param string $searchTerm = null - query to search against the cache
     * 
     * @return array
     */
    public function backslashSearch(?string $searchTerm = null) : array
    {
        if(! $this->searchCache()) {
            return [];
        }

        $cachePath = $this->checkDir();

        if(! is_file($cachePath)) {
            $this->buildCache();
        }

        $json = file_get_contents($cachePath);

        return $this->getResults($searchTerm, $json, 10);
    }
}