<?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\Str;

use App\Events\CourseSaved;

use App\Traits\HasContentElementsTrait;
use App\Traits\AppendAttributesTrait;
use App\Traits\VersioningTrait;
use App\Traits\SlugTrait;
use App\Traits\TagsTrait;
use App\Traits\HasPermissionsTrait;
use App\Traits\FindByTagsTrait;

use App\Models\Tag;
use App\Models\ContentElement;
use App\Models\CourseList;

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

class Course extends Model implements SearchResultContract
{
    use HasFactory;
    use SoftDeletes;
    use AppendAttributesTrait;
    use HasContentElementsTrait;
    use VersioningTrait;
    use SlugTrait;
    use TagsTrait;
    use HasPermissionsTrait;
    use FindByTagsTrait;

    protected $hidden = [
        'contentElements',
        'signed_url',
        'preview_url',
    ];

    public $append_attributes = [
        'actions',
        'full_type',
        'full_slug',
        'resource',
        'type',
        'name',
        'external_content',
        'anchor',
        //'version',
        //'can_be_published',
    ];

    protected $casts = [
        'unlisted' => 'boolean',
    ];


    public function saveCourse(array $input, $id = null)
    {
        if ($id) {
            $course = Course::findOrFail($id);
        } else {
            $course = new Course();
        }

        $course->save();

        $old_tags = $course->tags()->get();

        $course->saveVersion($input);

        // if we are creating a new course, also create a course description content element
        if (!$id) {
            if (!Arr::get($input, 'content')) {
                $input['content'] = [
                    [
                        'id' => 0,
                        'type' => 'course-description',
                        'pivot' => [
                            'contentable_id' => $course->id,
                            'contentable_type' => get_class($course),
                            'expandable' => null,
                            'filter' => 0,
                            'guest' => 0,
                            'no_margin' => 0,
                            'randomize' => 0,
                            'sort_order' => 1,
                            'unlisted' => 0,
                            'hide_print' => 0,
                        ],
                        'content' => [
                            'header' => '',
                            'body' => '',
                            'credit' => '',
                        ],
                    ]
                ];
            }

            foreach (Arr::get($input, 'content') as $index => $content) {
                if (!Arr::get($content, 'pivot.contentable_id')) {
                    $input['content'][$index]['pivot']['contentable_id'] = $course->id;
                }
                if (!Arr::get($content, 'pivot.contentable_type')) {
                    $input['content'][$index]['pivot']['contentable_type'] = get_class($course);
                }
            }
        }

        $course->saveContentElements($input);
        $course->saveTags($input);

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

        $new_tags = $course->tags()->get();

        $tags = collect($new_tags, $old_tags)->flatten()->unique(function ($tag) {
            return $tag->id;
        });

        foreach ($tags as $tag) {
            CourseList::whereHas('tags', function ($query) use ($tag) {
                return $query->where('tags.id', $tag->id);
            })
            ->each(function ($course_list) {
                cache()->tags([cache_name($course_list)])->flush();
                $content_element = $course_list->contentElement;
                if ($content_element) {
                    foreach ($content_element->contentables as $contentable) {
                        cache()->tags([cache_name($contentable->pageable)])->flush();
                    }
                }
            });
        }

        broadcast(new CourseSaved($course))->toOthers();
        $this->flushCache();

        return $course;
    }

    public function getAnchorAttribute()
    {
        return PageLink::convertAnchorText($this->course_description->content->header ?? 'course-'.$this->id);
    }

    public function getCourseLists()
    {
        return CourseList::whereHas('tags', function ($query) {
            return $query->whereIn('tags.id', $this->tags->pluck('id'));
        })->get();
    }

    public function getFullSlugAttribute()
    {
        return 'courses/'.$this->getSlug();
    }

    public function getCourseDescriptionAttribute()
    {
        $cache_name = cache_name($this).'-course-description';

        if (editing()) {
            $cache_name .= '-editing';
        }

        return cache()->tags([cache_name($this)])->rememberForever($cache_name, function () {
            return $this->content->filter(function ($content_element) {
                return $content_element->type === 'course-description';
            })->first();
        });
    }

    public function getExternalContentAttribute()
    {
        $cache_name = cache_name($this).'-external-content';

        if (editing()) {
            $cache_name .= '-editing';
        }

        return cache()->tags([cache_name($this)])->rememberForever($cache_name, function () {
            $external_content = $this->content->filter(function ($content_element) {
                return $content_element->type !== 'course-description';
            });

            if ($external_content->count()) {
                return $external_content->load('content');
            }

            if ($this->course_description) {
                return collect([$this->course_description->load('content')]);
            } else {
                return collect();
            }
        });
    }

    /*
    public function getExternalContentRendersAttribute()
    {
        return $this->external_content->map(function ($content) {
            return $content->renderView($this, $this->external_content, false, false, $content->pivot->sort_order);
        });
    }
     */

    public function flushCache()
    {
        cache()->tags([cache_name($this)])->flush();

        CourseList::whereHas('tags', function ($query) {
            return $query->whereIn('tags.id', $this->tags->pluck('id'));
        })
        ->each(function ($course_list) {
            cache()->tags([cache_name($course_list)])->flush();
            if ($course_list->contentElement) {
                foreach ($course_list->contentElement->contentables as $contentable) {
                    cache()->tags([cache_name($contentable->pageable)])->flush();
                }
            }
        });

        return $this;
    }
}
