<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Product extends Model
{
    protected $fillable = [
        'woo_id',
        'title', 'title_en', 'slug', 'brand_id', 'type',
        'description', 'features', 'warranty', 'package_type',
        'amadast_product_type_id', 'amadast_product_type_title', 'tags',
        'featured_image', 'featured_image_alt',
        'seo_title', 'seo_description', 'seo_keywords', 'seo_schema',
        'is_active', 'is_amazing_special', 'is_amazing_offer', 'special_offer_ends_at', 'sort_order', 'sales', 'rating',
    ];

    protected $casts = [
        'is_active'           => 'boolean',
        'is_amazing_special'  => 'boolean',
        'is_amazing_offer'    => 'boolean',
        'special_offer_ends_at' => 'datetime',
    ];

    public static function packageTypes(): array
    {
        return [
            1  => 'کارتن سایز 1 — 200 × 150 × 100 میلیمتر',
            2  => 'کارتن سایز 2 — 200 × 150 × 100 میلیمتر',
            3  => 'کارتن سایز 3 — 200 × 200 × 150 میلیمتر',
            4  => 'کارتن سایز 4 — 300 × 200 × 200 میلیمتر',
            5  => 'کارتن سایز 5 — 350 × 250 × 200 میلیمتر',
            6  => 'کارتن سایز 6 — 450 × 250 × 200 میلیمتر',
            7  => 'کارتن سایز 7 — 400 × 300 × 250 میلیمتر',
            8  => 'کارتن سایز 8 — 450 × 400 × 300 میلیمتر',
            9  => 'کارتن سایز 9 — 550 × 450 × 350 میلیمتر',
            10 => 'کارتن سایز 10',
            11 => 'کارتن بزرگتر از سایز 10',
            12 => 'پاکت های پستی (A4، A5 و ...)',
            13 => 'بسته‌بندی برنج',
            14 => 'پاکت پستی (A3)',
        ];
    }

    public function getRouteKeyName(): string
    {
        return 'slug';
    }

    public function brand()
    {
        return $this->belongsTo(Brand::class);
    }

    public function categories()
    {
        return $this->belongsToMany(
            ProductCategory::class,
            'product_category',
            'product_id',
            'category_id'
        );
    }

    public function images()
    {
        return $this->hasMany(ProductImage::class)->orderBy('sort_order');
    }

    public function attributes()
    {
        return $this->hasMany(ProductAttribute::class)->orderBy('sort_order');
    }

    public function variants()
    {
        return $this->hasMany(ProductVariant::class)->orderBy('sort_order');
    }

    public function reviews()
    {
        return $this->hasMany(ProductReview::class)->latest();
    }

    public function similarProducts()
    {
        return $this->belongsToMany(
            Product::class,
            'product_similar',
            'product_id',
            'similar_product_id'
        )->withPivot('sort_order')->orderByPivot('sort_order');
    }

    /**
     * Storefront similar products: manual picks first, else random from shared categories.
     *
     * @return array{products: \Illuminate\Support\Collection, is_manual: bool}
     */
    public function resolveSimilarProducts(int $limit = 6): array
    {
        $manual = $this->similarProducts()
            ->where('is_active', true)
            ->with(['variants', 'images'])
            ->get();

        if ($manual->isNotEmpty()) {
            return ['products' => static::sortInStockFirst($manual), 'is_manual' => true];
        }

        $categoryIds = $this->categories()->pluck('product_categories.id');
        if ($categoryIds->isEmpty()) {
            return ['products' => collect(), 'is_manual' => false];
        }

        $fallback = static::query()
            ->where('is_active', true)
            ->where('id', '!=', $this->id)
            ->whereHas('categories', fn ($q) => $q->whereIn('product_categories.id', $categoryIds))
            ->with(['variants', 'images'])
            ->orderInStockFirst()
            ->inRandomOrder()
            ->limit($limit)
            ->get();

        return ['products' => $fallback, 'is_manual' => false];
    }

    /**
     * Default variant — the one marked is_default, or first available, or just first.
     */
    public function defaultVariant(): ?ProductVariant
    {
        $variants = $this->variants;
        return $variants->firstWhere('is_default', true)
            ?? $variants->where('is_active', true)->first()
            ?? $variants->first();
    }

    /**
     * In-stock check based on the DEFAULT variant only.
     * Other variants' stock doesn't matter — what's shown on the card is the default.
     */
    public function isInStock(): bool
    {
        $v = $this->defaultVariant();
        return $v !== null && (int) $v->stock > 0;
    }

    /**
     * SQL expression: 0 = in stock (default variant), 1 = out of stock.
     * Matches defaultVariant() priority: is_default → first active → first.
     */
    public static function outOfStockRankSql(): string
    {
        return '(CASE WHEN COALESCE(
            (SELECT stock FROM product_variants WHERE product_id = products.id AND is_default = 1 LIMIT 1),
            (SELECT stock FROM product_variants WHERE product_id = products.id AND is_active = 1 ORDER BY sort_order ASC, id ASC LIMIT 1),
            (SELECT stock FROM product_variants WHERE product_id = products.id ORDER BY sort_order ASC, id ASC LIMIT 1),
            0
        ) > 0 THEN 0 ELSE 1 END)';
    }

    /**
     * Always put out-of-stock products after in-stock ones (then caller adds other sorts).
     */
    public function scopeOrderInStockFirst($query)
    {
        return $query->orderByRaw(self::outOfStockRankSql() . ' ASC');
    }

    /**
     * Re-order an already-loaded collection: in-stock first.
     */
    public static function sortInStockFirst($collection)
    {
        return $collection->sortBy(fn (self $p) => $p->isInStock() ? 0 : 1)->values();
    }

    public static function generateSlug(string $name, ?int $excludeId = null): string
    {
        $base = str_replace(' ', '-', trim($name));
        $slug = $base;
        $counter = 1;
        while (
            static::where('slug', $slug)
                ->when($excludeId, fn($q) => $q->where('id', '!=', $excludeId))
                ->exists()
        ) {
            $slug = $base . '-' . $counter++;
        }
        return $slug;
    }
}
