<?php

namespace App\Models;

use App\Libs\Database\Eloquent\ContentTypeCollection;
use App\Libs\Facades\Localization;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Arr;
use DateTime;

abstract class ContentTypeModel extends BaseModel
{
    use SoftDeletes;

    protected $websiteAttributes = array(
        "website_id", "website_object_id", "slug", "uri", "lang_slug", "lang_uri", "template", "status", "sub_type", "position", "content_type",
        "is_shared", "publish_on", "lang_publish_on"
    );
    protected $related = array();

    public function websites()
    {
        return $this->morphMany(WebsiteObject::class, "objectable", "object_type", "object_id");
    }

    public function scopeFull($query, $forceLanguage = false)
    {
        $query->setEagerLoads(array());
        $languageRelation = $this->languages();
        $languageTable = $languageRelation->getRelated()->getTable();
        $languageFK = $languageRelation->getQualifiedForeignKeyName();
        $lang = $forceLanguage ? $forceLanguage : Localization::getActiveLocale();
        $query->join($languageTable, function ($join) use ($lang, $languageTable, $languageFK) {
            $join->on("{$this->getTable()}.id", "=", "{$languageFK}")
                ->where("{$languageTable}.language_id", "=", $lang);
        });

        $websiteRelationship = $this->websites();
        $websiteObjectModel = $websiteRelationship->getRelated();
        $websiteObjectFK = $websiteRelationship->getQualifiedForeignKeyName();
        $model = $this;

        $query->join($websiteObjectModel->getTable(),
            function ($join) use ($model, $websiteObjectFK, $websiteRelationship) {
                $join->on($model->getQualifiedKeyName(), "=", $websiteObjectFK)
                    ->where($websiteRelationship->getMorphType(), "=",  get_class($model));
            });

        $query->join('website_objects_lang',
            function ($join) use ($lang) {
                $join->on('website_objects_lang.website_object_id', "=", 'website_objects.website_object_id')
                    ->where('website_objects_lang.wo_language_id', "=", $lang);
            });

        $query->where("{$websiteObjectModel->getTable()}.website_id", "=", 1);
        return $query;
    }

    public function scopeLang($query, $forceLanguage = false)
    {
        $query->setEagerLoads(array());
        $languageRelation = $this->languages();
        $languageTable = $languageRelation->getRelated()->getTable();
        $languageFK = $languageRelation->getQualifiedForeignKeyName();
        $lang = $forceLanguage ? $forceLanguage : Localization::getActiveLocale();
        $query->join($languageTable, function ($join) use ($lang, $languageTable, $languageFK) {
            $join->on("{$this->getTable()}.id", "=", "{$languageFK}")
                ->where("{$languageTable}.language_id", "=", $lang);
        });
        return $query;
    }

    public function scopeWebsite($query)
    {
        $query->setEagerLoads(Arr::except($query->getEagerLoads(), "websites"));


        $websiteRelationship = $this->websites();
        $websiteObjectModel = $websiteRelationship->getRelated();
        $websiteObjectFK = $websiteRelationship->getQualifiedForeignKeyName();
        $model = $this;

        $query->join($websiteObjectModel->getTable(),
            function ($join) use ($model, $websiteObjectFK, $websiteRelationship) {
                $join->on($model->getQualifiedKeyName(), "=", $websiteObjectFK)
                    ->where($websiteRelationship->getMorphType(), "=", class_basename($model));
            });
        /*
        $query->join('website_objects_lang',
            function($join) use ($lang){
                $join->on('website_objects_lang.website_object_id', "=", 'website_objects.website_object_id')
                    ->where('website_objects_lang.wo_language_id', "=", $lang);
            });
        */
        $query->where("{$websiteObjectModel->getTable()}.website_id", "=", Localization::getWebsite()->id);
        return $query;

    }

    public function hasWebsite($websiteId)
    {
        $websites = $this->websites;
        if (empty($websites)) {
            return false;
        }

        $website = $websites->findByWebsite($websiteId);
        return !empty($website);
    }

    public function getAttribute($key)
    {
        if (parent::keyExists($key)) {
            return parent::getAttribute($key);
        }

        $inWebsiteAttributes = in_array($key, $this->websiteAttributes);
        if ($this->exists && $inWebsiteAttributes) {
            $websiteEntry = $this->getActiveWebsiteEntry();

            if (!empty($websiteEntry) && !empty($websiteEntry->$key)) {

                return $websiteEntry->$key;
            }
        }

        return null;
    }

    public function getActiveWebsiteEntry()
    {
        $activeWebsite = Localization::getWebsite();
        if (empty($activeWebsite)) {
            return null;
        }

        $websitesData = $this->websites;
        if (empty($websitesData)) {
            return null;
        }

        $website = $websitesData->filter(function ($websiteData) use ($activeWebsite) {
            return $websiteData->website_id == $activeWebsite->id;
        })->first();

        return $website;
    }

    public function related($type, $order = "position", $withPerType = array())
    {
        if (isset($this->related[$type])) {
            return $this->related[$type];
        }

        $activeWebsite = $this->getActiveWebsiteEntry();

        if (empty($activeWebsite)) {
            $this->related[$type] = null;
            return $this->related[$type];
        }
        $query = $activeWebsite->related()->wherePivot("type", $type);
        if ($order == "position") {
            $query->orderBy("related.position", "asc");
        }

        $objects = $query->get();

        $objects->load("objectable");

        foreach ($withPerType as $objectType => $with) {
            load_polymorphic_dependencies($objects, "objectable", $objectType, $with, "object_id", "object_type");
        }

        $objects = $objects->getObjectables();

        if ($order != "position") {
            $objects = $objects->sortBy(function ($model) {
                return $model->title;
            });
        }

        $this->related[$type] = $objects;
        return $this->related[$type];

    }

    public function setRelated($type, $collection)
    {
        $this->related[$type] = $collection;
    }

    public function toArray()
    {
        $array = parent::toArray();
        if (isset($this->relations["websites"])) {
            foreach ($this->websiteAttributes as $websiteAttribute) {
                if (!in_array($websiteAttribute, $this->hidden)) {
                    $array[$websiteAttribute] = $this->$websiteAttribute;
                    if ($array[$websiteAttribute] instanceof DateTime) {
                        $array[$websiteAttribute] = $array[$websiteAttribute]->format($this->getDateFormat());
                    }
                }
            }
        }
        return $array;
    }

    public function newCollection(array $models = array())
    {
        return new ContentTypeCollection($models);
    }

    public function keyExists($key)
    {
        return parent::keyExists($key) || in_array($key, $this->websiteAttributes);
    }

    public function scopeNoWebsiteNoLang($query)
    {
        $query->setEagerLoads(array());
        return $query;
    }
}

