<?php

namespace App\Models\Shop;

use App\Models\Botanic\Specie;
use App\Models\Botanic\Variety;
use App\Traits\Model\HasComments;
use App\Traits\Model\Imageable;
use Cviebrock\EloquentSluggable\Sluggable;
use Fico7489\Laravel\EloquentJoin\Traits\EloquentJoin;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
use Illuminate\Database\Eloquent\Relations\MorphTo;
use Illuminate\Database\Eloquent\Relations\MorphToMany;
use Illuminate\Database\Eloquent\SoftDeletes;
use Kirschbaum\PowerJoins\PowerJoins;
use Laravel\Scout\Searchable;
use RalphJSmit\Laravel\SEO\Support\HasSEO;
use RalphJSmit\Laravel\SEO\Support\SEOData;
use Rinvex\Categories\Traits\Categorizable;
use Rinvex\Tags\Traits\Taggable;
use Spatie\MediaLibrary\HasMedia;
use Staudenmeir\EloquentHasManyDeep\HasRelationships;
use Venturecraft\Revisionable\RevisionableTrait;
use Wildside\Userstamps\Userstamps;

class Article extends Model implements HasMedia
{
    use Categorizable;
    use EloquentJoin;
    use HasComments;
    use HasRelationships;
    use HasSEO;
    use Imageable;
    use Powerjoins;
    use RevisionableTrait;
    use Searchable;
    use Sluggable;
    use SoftDeletes;
    use Taggable;
    use UserStamps;

    protected $guarded = ['id'];

    protected $table = 'shop_articles';

    protected $dontKeepRevisionOf = ['updated_by', 'updated_at'];

    public function article_nature(): BelongsTo
    {
        return $this->belongsTo(ArticleNature::class);
    }

    public function offers(): HasMany
    {
        return $this->hasMany(Offer::class);
    }

    public function price_lists()
    {
        return $this->hasManyDeep(
            PriceList::class,
            [Offer::class, Tariff::class],
            ['article_id', 'id'],
            ['id', 'tariff_id'],
        );
    }

    public function prices()
    {
        return $this->hasManyDeep(
            PriceListValue::class,
            [Offer::class, Tariff::class, PriceList::class],
            ['article_id', 'id', 'tariff_id'],
            ['id', 'tariff_id', 'id'],
        );
    }

    public function product(): MorphTo
    {
        return $this->morphTo();
    }

    public function siblings(): HasMany
    {
        return $this->hasMany(Article::class, 'name', 'name');
    }

    public function tags(): MorphToMany
    {
        return $this->morphToMany(Tag::class, 'taggable');
    }

    public function tariffs(): HasManyThrough
    {
        return $this->hasManyThrough(Tariff::class, Offer::class, 'article_id', 'id', 'id', 'tariff_id');
        // return $this->belongsToMany(Tariff::class, Offer::$table, 'id', 'id', 'tariff_id', 'tariff_id');
    }

    public function scopeByArticle($query, $id)
    {
        return $query->where($this->table.'.id', $id);
    }

    public function scopeByAutocomplete($query, $str)
    {
        return $query->where($this->table.'.name', 'LIKE', '%'.$str.'%');
    }

    public function scopeRawSearch($query, $str)
    {
        return $query->where($this->table.'.name', 'LIKE', '%'.$str.'%');
    }

    public function scopeByArticleNature($query, $id)
    {
        return $id ? $query->where($this->table.'.article_nature_id', $id) : $query;
    }

    public function scopeByArticleNatures($query, $ids)
    {
        return $ids ? $query->whereIn($this->table.'.article_nature_id', $ids) : $query;
    }

    public function scopeByCategories($query, $categoriesId)
    {
        return $categoriesId ? $query->whereHas('categories', function ($query) use ($categoriesId) {
            $query->whereIn('id', $categoriesId)->whereNull('deleted_at');
        }) : $query;
    }

    public function scopeByCategoryParent($query, $categoryId)
    {
        $category = Category::find($categoryId);
        $left = $category->_lft ?? 0;
        $right = $category->_rgt ?? 0;

        return $categoryId ? $query->whereHas('categories', function ($query) use ($left, $right) {
            $query->where('_lft', '>=', $left)->where('_rgt', '<=', $right)->whereNull('deleted_at');
        }) : $query;
    }

    public function scopeByCategory($query, $categoryId)
    {
        return $categoryId ? $query->whereHas('categories', function ($query) use ($categoryId) {
            $query->where('id', $categoryId)->whereNull('deleted_at');
        }) : $query;
    }

    public function scopeBotanic($query)
    {
        return $query->whereIn($this->table.'.product_type', [Variety::class, Specie::class]);
    }

    public function scopeByIDs($query, $ids)
    {
        return $query->whereIN($this->table.'.id', $ids);
    }

    public function scopeMerchandise($query)
    {
        return $query->byProduct(Merchandise::class);
    }

    public function scopeVisible($query)
    {
        return $query->where($this->table.'.visible', 1);
    }

    public function scopeHomepage($query)
    {
        return $query->where($this->table.'.homepage', 1);
    }

    public function scopeByProduct($query, $model)
    {
        return $model ? $query->where($this->table.'.product_type', $model) : $query;
    }

    public function scopeByProductId($query, $productId)
    {
        return $productId ? $query->where($this->table.'.product_id', $productId) : $query;
    }

    public function scopeBySlug($query, $slug)
    {
        return $slug ? $query->where($this->table.'.slug', $slug) : $query;
    }

    public function scopeByTag($query, $tagId)
    {
        return $tagId ? $query->whereHas('tags', function ($query) use ($tagId) {
            $query->byId($tagId);
        })->orWhereHasMorph('product', [Variety::class], function($query) use ($tagId) {
            $query->whereHas('tags', function ($query) use ($tagId) {
                $query->where('id', $tagId);
            });
        }) : $query;
    }

    public function scopeByTags($query, $tags)
    {
        return $tags ? $query->whereHas('tags', function ($query) use ($tags) {
            $query->byIds($tags);
        })->orWhereHasMorph('product', [Variety::class], function($query) use ($tags) {
            $query->whereHas('tags', function ($query) use ($tags) {
                $query->whereIntegerInRaw('id', $tags);
            });
        }) : $query;
    }

    public function scopeWithOffers($query)
    {
        return $query->has('offers');
    }

    public function scopeWithAvailableOffers($query, $saleChannelId = false)
    {
        return $query->visible()->whereHas('offers', function ($query) use ($saleChannelId) {
            $query->active()->byStockAvailable();

            if ($saleChannelId) {
                $query->bySaleChannel($saleChannelId);
            }
        });
    }

    public function toSearchableArray(): array
    {
        $description = $this->description;
        $product = $this->product ?? false;

        if (is_object($product)) {
            $description .= ' '.$product ? $product->description : '';
            $description .= ' '.$product ? $product->plus ?? '' : '';

            $specie = $product ? $product->specie : false;
            $description .= ' '.$specie ? $specie->description ?? '' : '';
        }

        return [
            'id' => (int) $this->id,
            'article_nature_id' => $this->article_nature_id,
            'name' => $this->name,
            'description' => html_entity_decode(strip_tags($description)),
        ];
    }

    public function getDynamicSEOData(): SEOData
    {
        // $pathToFeaturedImageRelativeToPublicPath = // ..;

        // Override only the properties you want:
        return new SEOData(
            title: $this->name,
            description: $this->description,
            // image: $pathToFeaturedImageRelativeToPublicPath,
        );
    }

    public function sluggable(): array
    {
        return [
            'slug' => [
                'source' => 'name',
            ],
        ];
    }
}
