<?php

namespace App\Models\Shop;

use App\Models\Botanic\Specie;
use App\Models\Botanic\Variety;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\MorphToMany;
use Illuminate\Support\Facades\DB;
use Rinvex\Tags\Models\Tag as parentTag;

class Tag extends parentTag
{
    public $translatable = [];

    protected $guarded = ['id'];

    protected $fillable = [
        'slug',
        'name',
        'description',
        'sort_order',
        'group',
        'tag_group_id',
    ];

    // TODO
    public function offers(): MorphToMany
    {
        return $this->articles();
    }

    public function articles(): MorphToMany
    {
        return $this->morphedByMany(Article::class, 'taggable');
    }

    public function categories(): MorphToMany
    {
        return $this->morphedByMany(Category::class, 'taggable');
    }

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

    public function shelves(): MorphToMany
    {
        return $this->morphedByMany(Shelve::class, 'taggable');
    }

    public function species(): MorphToMany
    {
        return $this->morphedByMany(Specie::class, 'taggable');
    }

    public function varieties(): MorphToMany
    {
        return $this->morphedByMany(Variety::class, 'taggable');
    }

    public function merchandises(): MorphToMany
    {
        return $this->morphedByMany(Merchandise::class, 'taggable');
    }

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

    public function scopeWithCountArticlesByCategory($query, $category_id)
    {
        return $query->withCount([
            'articles' => function ($query) use ($category_id) {
                $query->byCategoryParent($category_id);
            },
        ]);
    }

    public static function countArticles($categoryId)
    {
        DB::table('tags')
            // Articles directement liés au tag, filtrés par catégorie
            ->leftJoin('taggables as direct', function ($join) {
                $join->on('tags.id', '=', 'direct.tag_id')
                    ->where('direct.taggable_type', '=', Article::class);
            })
            ->leftJoin('shop_articles', 'direct.taggable_id', '=', 'shop_articles.id')
            ->whereExists(function ($query) use ($categoryId) {
                $query->select(DB::raw(1))
                    ->from('categories')
                    ->whereColumn('categories.id', 'shop_articles.category_id')
                    ->where('_lft', '>=', DB::raw("(SELECT _lft FROM categories WHERE id = {$categoryId})"))
                    ->where('_rgt', '<=', DB::raw("(SELECT _rgt FROM categories WHERE id = {$categoryId})"));
            })

            // Articles liés via une variété ayant le tag, filtrés par catégorie
            ->leftJoin('taggables as via_variety', function ($join) {
                $join->on('tags.id', '=', 'via_variety.tag_id')
                    ->where('via_variety.taggable_type', '=', Variety::class);
            })
            ->leftJoin('botanic_varieties', 'via_variety.taggable_id', '=', 'botanic_varieties.id')
            ->leftJoin('shop_articles as indirect_articles', function ($join) {
                $join->on('varieties.id', '=', 'indirect_articles.product_id')
                    ->where('indirect_articles.product_type', '=', Variety::class);
            })
            ->whereExists(function ($query) use ($categoryId) {
                $query->select(DB::raw(1))
                    ->from('categories')
                    ->whereColumn('categories.id', 'indirect_articles.category_id')
                    ->where('_lft', '>=', DB::raw("(SELECT _lft FROM categories WHERE id = {$categoryId})"))
                    ->where('_rgt', '<=', DB::raw("(SELECT _rgt FROM categories WHERE id = {$categoryId})"));
            })

            // Combinaison des deux types de liens et comptage
            ->select('tags.id', 'tags.name', DB::raw('COUNT(DISTINCT shop_articles.id) + COUNT(DISTINCT indirect_articles.id) as article_count'))
            ->groupBy('tags.id', 'tags.name')
            ->get();
    }

    public function scopeWithFilteredArticleCounts($query, $categoryId)
    {
        return $query->withCount([
            // Articles directement liés au tag et filtrés par catégorie
            'articles as direct_article_count' => function ($query) use ($categoryId) {
                $query->byCategoryParent($categoryId);
            },
            
            // Articles liés via Variety et filtrés par catégorie sur les articles eux-mêmes
            'articles as indirect_article_count' => function ($query) use ($categoryId) {
                $query->whereHasMorph('product', [Variety::class], function ($subQuery) {
                    // Pas de catégorie sur Variety, pas de filtre ici
                })->byCategoryParent($categoryId);
            },
        ])
        ->havingRaw('(COALESCE(direct_article_count, 0) + COALESCE(indirect_article_count, 0)) > 0'); // Filtre les tags avec au moins un article
    }

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

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