<?php
/**
 * The model for Page. Don't use directly in most situations if you don't know how to filter out actual pages. Use the \Page class or \Listing
 * @author Rihards Silins <rihards.silins@mtcmedia.co.uk>
 * @copyright MTC media Ltd
 * @version 1 15/12/2016
 */

namespace Mtc\Cms\Models;

use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Cache;
use Spatie\Sitemap\Contracts\Sitemapable;
use Spatie\Sitemap\Tags\Url;


class Page extends Model implements Sitemapable
{
    /**
     * Indicates if the model should be timestamped.
     * @var bool
     */
    public $timestamps = false;

    protected $fillable = [
        'sub_id',
        'order',
        'type',
        'title',
        'slug',
        'url',
        'innav',
        'searchable',
        'lock',
        'hide_in_cms',
        'allow_delete',
        'allow_update',
        'redchild',
        'listing_container',
        'draft_for_page_id',
        'history_lock',
        'review_status',
        'noindex',
        'search_title',
        'search_content',
        'created',
        'updated',
        'published',
        'template',
        'layout',
        'logic',
        'seo_title',
        'seo_keywords',
        'seo_description',
        'frontpage',
        'contact_page',
        'ajax',
        'directly_viewable',
        'versions',
        'author_name',
        'author_admin_user_id',
        'comment',
        'data1',
        'data2',
        'data3',
    ];

    public static function boot(): void
    {
        parent::boot();

        self::saved(function (self $page) {
            // Clear page cache when any page is updated or created
            Cache::forget("cms_page::{$page->id}");
        });

        self::deleted(function (self $page) {
            // Clear page cache when any page is deleted
            Cache::forget("cms_page::{$page->id}");
        });
    }

    /**
     * Whether or not pages parent page is a listing_container
     * @return int
     */
    public function getListingItemAttribute() {
        $page_object = self::find($this->sub_id);
        if ($page_object === null) {
            return 0;
        }
        return $page_object->listing_container;
    }


    public function lists()
    {
        return $this->hasMany("Mtc\Cms\Models\PageList", "page_id");
    }


    public function getAdminUrl()
    {
        return "/cms/admin/content_manager/?page={$this->id}";
    }


    public function replicateWithRelations()
    {
        $clone = $this->replicate();
        $clone->save();

        foreach ($this->lists as $list) {
            $list_clone = $list->replicate();
            $clone->lists()->save($list_clone);

            foreach ($list->items as $list_item) {
                $list_item_clone = $list_item->replicate();
                $list_item_clone->page_id = $clone->id;
                $list_clone->items()->save($list_item_clone);

                foreach ($list_item->data as $list_item_datum) {
                    $list_item_datum_clone = $list_item_datum->replicate();
                    $list_item_datum_clone->page_id = $clone->id;
                    $list_item_datum_clone->page_list_id = $list_clone->id;
                    $list_item_clone->data()->save($list_item_datum_clone);
                }
            }
        }

        foreach ($this->children as $sub_page) {
            $sub_page_clone = $sub_page->replicateWithRelations();
            $clone->children()->save($sub_page_clone);
        }

        return $clone;
    }


    public static function getExportableFields()
    {
        return [
            'pages.id',
            'pages.title',
            'pages.slug',
            'pages.published',
            'pages.seo_title',
            'pages.seo_keywords',
            'pages.seo_description',
        ];
    }


    public function updateSlug(string $slug)
    {
        $this->slug = $slug;

        return $this->save();
    }


    public function parentPage()
    {
        return $this->hasOne(Page::class, 'id', 'sub_id');
    }


    public function children()
    {
        return $this->hasMany(Page::class, "sub_id");
    }


    public function getAncestors()
    {
        $ancestors = new Collection;

        if ($this->parentPage) {
            $ancestors->push($this->parentPage);
            $ancestors = $ancestors->merge($this->parentPage->getAncestors());
        }

        return $ancestors;
    }


    public function getTreeOfContainers(int $parent_id = 0)
    {
        $tree = [];

        $root_page = $this->getAncestors()->last();

        if (! $root_page) {
            $root_page = $this;
        }

        $tree[$root_page->id] = $root_page->title;

        $pages = self::query()
            ->where('listing_container', 1)
            ->where('sub_id', '!=', '0')
            ->get()
        ;

        foreach ($pages as $page) {
            $ancestors = $page->getAncestors();
            if ($ancestors->last()->id != $root_page->id) continue;

            $title_segments = [ $page->title ];
            foreach ($ancestors as $ancestor) {
                $title_segments[] = $ancestor->title;
            }

            $tree[$page->id] = implode(' / ', array_reverse($title_segments));
        }

        return $tree;
    }


    public function legacy()
    {
        return (new \Page($this->id));
    }

    public function toSitemapTag(): Url | string | array
    {
        return Url::create(config('app.url') . $this->legacy()->url)
            ->setLastModificationDate(Carbon::create($this->updated))
            ->setChangeFrequency(Url::CHANGE_FREQUENCY_MONTHLY)
            ->setPriority(0.5)
        ;
    }


    public function getAllDescendants() : Collection
    {
        $pages = collect([]);

        foreach ($this->children as $temp_page) {
            $pages->push($temp_page);
            if ($temp_page->children->count()) {
                $pages = $pages->merge($temp_page->getAllDescendants());
            }
        }

        return $pages;
    }

    /**
     * Scope a query to only include published pages.
     * @param  \Illuminate\Database\Eloquent\Builder  $query
     *
     * @return \Illuminate\Database\Eloquent\Builder
     * */
    public function scopePublished($query)
    {
        return $query->where('published', 1);
    }

    /**
     * Scope a query to only include default type pages.
     * @param  \Illuminate\Database\Eloquent\Builder  $query
     *
     * @return \Illuminate\Database\Eloquent\Builder
     * */
    public function scopeDefault($query)
    {
        return $query->where('type', 'default');
    }

}
