<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

use Illuminate\Support\Arr;
use Illuminate\Support\Collection;

use App\Traits\PhotosTrait;
use App\Traits\TagsTrait;
use App\Traits\FindByTagsTrait;
use App\Traits\HasPermissionsTrait;

use App\Models\User;

use App\Contracts\SearchResultContract;
use App\Utilities\SearchResult;

use App\Utilities\PageLink;

class StaffProfile extends Model implements SearchResultContract
{
    use HasFactory;
    use PhotosTrait;
    use TagsTrait;
    use SoftDeletes;
    use FindByTagsTrait;
    use HasPermissionsTrait;

    protected $appends = ['full_name', 'anchor'];

    protected $casts = [
        'published_at' => 'datetime',
    ];

    public function getFullNameAttribute()
    {
        return $this->first_name.' '.$this->last_name;
    }

    public function getNameAttribute()
    {
        return $this->full_name;
    }

    public function saveStaffProfile(array $input, $id = null)
    {
        if ($id) {
            $staff_profile = StaffProfile::findOrFail($id);
        } else {
            $staff_profile = new StaffProfile();
        }

        $staff_profile->first_name = Arr::get($input, 'first_name');
        $staff_profile->last_name = Arr::get($input, 'last_name');
        $staff_profile->bio_draft = Arr::get($input, 'bio_draft');
        $staff_profile->credentials = Arr::get($input, 'credentials');
        $staff_profile->departments = Arr::get($input, 'departments');

        if (auth()->user()?->hasRole('staff-profiles-manager')) {
            $user = User::find(Arr::get($input, 'user_id'));

            if ($user) {
                $staff_profile->user_id = $user->id;
            } else {
                $staff_profile->user_id = null;
            }
        }

        $staff_profile->save();

        $staff_profile->saveSinglePhoto($input);
        $staff_profile->saveTags($input);

        cache()->tags([cache_name($staff_profile)])->flush();

        return $staff_profile;
    }

    public function user()
    {
        return $this->belongsTo(User::class);
    }

    public function getAnchorAttribute()
    {
        return PageLink::convertAnchorText($this->full_name ?? 'staff-profile-'.$this->id);
    }

    public function loadCollectionAttributes(Collection $items)
    {
        if (!$items->count()) {
            return $items;
        }
        return $items->load('user', 'tags', 'photos');
    }


    public function getSearchFieldsAttribute()
    {
        return [
            'first_name',
            'last_name',
            'bio',
            'credentials',
            'departments',
        ];
    }

    public static function searchResults($terms)
    {
        $staff_profiles = self::where(function ($query) use ($terms) {
            $query->where(function ($query) use ($terms) {
                $first = true;
                foreach ($terms as $term) {
                    foreach ((new StaffProfile())->search_fields as $field) {
                        if ($first) {
                            $query->where($field, 'LIKE', '%'.$term.'%');
                            $first = false;
                        } else {
                            $query->orWhere($field, 'LIKE', '%'.$term.'%');
                        }
                    }
                }
            })
            ->orWhereHas('tags', function ($query) use ($terms) {
                $first = true;
                foreach ($terms as $term) {
                    if ($first) {
                        $query->where('name', 'LIKE', '%'.$term.'%');
                        $first = false;
                    } else {
                        $query->orWhere('name', 'LIKE', '%'.$term.'%');
                    }
                }
            });
        })
        ->get();

        $results = collect();

        foreach ($staff_profiles as $staff_profile) {
            $search_result = new SearchResult(
                'staff-profile',
                $staff_profile->id,
                $staff_profile->full_slug,
                $staff_profile->getSearchResultTitle(),
                $staff_profile->getSearchResultPreview($terms),
                $staff_profile->getSearchResultRank($terms),
                SearchResult::urlText($staff_profile->full_slug),
                $staff_profile->updated_at,
                $staff_profile->getSearchResultPhoto($terms),
            );
            $results->push($search_result);
        }

        return $results;
    }

    public function getSearchResultTitle($default = null)
    {
        return $this->full_name;
    }

    public function getSearchResultPreview($terms)
    {
        return SearchResult::truncatePreview($this->bio, $terms);
    }

    public function getSearchResultRank($terms)
    {
        $rank = 0;
        foreach ($terms as $term) {
            $rank += mb_substr_count($this->full_name, $term);
            $rank += mb_substr_count($this->bio, $term) * 0.5;
            $rank += mb_substr_count($this->departments, $term) * 0.5;
        }
        return $rank;
    }

    public function getSearchResultPhoto($terms)
    {
        return $this->photos->first();
    }

    public function publish()
    {
        if ($this->bio !== $this->bio_draft || !$this->published_at) {
            $this->bio = $this->bio_draft;
            $this->published_at = now();
            $this->save();
            $this->refresh();
        }
    }
}
