<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Product extends Model
{
    use HasFactory;

    protected $fillable = [
        'name',
        'slug',
        'description',
        'short_description',
        'price',
        'unit',
        'sale_price',
        'sku',
        'stock_quantity',
        'manage_stock',
        'in_stock',
        'images',
        'weight',
        'origin',
        'category_id',
        'is_featured',
        'is_active',
        'rating',
        'reviews_count',
        'meta_data',
        'variants',
    ];

    protected $casts = [
        'price' => 'decimal:2',
        'sale_price' => 'decimal:2',
        'manage_stock' => 'boolean',
        'in_stock' => 'boolean',
        'is_featured' => 'boolean',
        'is_active' => 'boolean',
        'rating' => 'decimal:2',
        'images' => 'array',
        'meta_data' => 'array',
        'variants' => 'array',
    ];

    /**
     * Get the category that owns the product.
     */
    public function category()
    {
        return $this->belongsTo(Category::class);
    }

    /**
     * Get the order items for the product.
     */
    public function orderItems()
    {
        return $this->hasMany(OrderItem::class);
    }

    /**
     * Get the cart items for the product.
     */
    public function cartItems()
    {
        return $this->hasMany(Cart::class);
    }

    /**
     * Determine whether the product has configured variants.
     */
    public function hasVariants(): bool
    {
        return ! empty($this->variants);
    }

    /**
     * Return normalized variant data with stable indexes.
     */
    public function normalizedVariants(): array
    {
        return collect($this->variants ?? [])
            ->values()
            ->map(fn ($variant, $index) => $this->normalizeVariantRow($variant, $index))
            ->all();
    }

    /**
     * Resolve a variant by its index from the configured variants array.
     */
    public function resolveVariantByIndex(?int $index): ?array
    {
        $variants = $this->normalizedVariants();

        if ($index === null) {
            return $variants[0] ?? null;
        }

        return $variants[$index] ?? null;
    }

    /**
     * Resolve a variant by label when an index is not available.
     */
    public function resolveVariantByLabel(?string $label): ?array
    {
        if ($label === null || $label === '') {
            return $this->resolveVariantByIndex(null);
        }

        foreach ($this->normalizedVariants() as $variant) {
            if (strcasecmp((string) $variant['label'], $label) === 0) {
                return $variant;
            }
        }

        return null;
    }

    /**
     * Get the default variant for storefront and cart fallbacks.
     */
    public function defaultVariant(): ?array
    {
        return $this->resolveVariantByIndex(0);
    }

    /**
     * Normalize a raw variant row into a stable storefront payload.
     */
    private function normalizeVariantRow($variant, int $index): array
    {
        $variant = is_array($variant) ? $variant : [];
        $salePrice = array_key_exists('sale_price', $variant) && $variant['sale_price'] !== null && $variant['sale_price'] !== ''
            ? (float) $variant['sale_price']
            : null;
        $finalPrice = (float) ($variant['final_price'] ?? $this->price ?? 0);

        return [
            'index' => $index,
            'label' => $variant['label'] ?? ('Variant '.($index + 1)),
            'unit' => $variant['unit'] ?? $this->unit,
            'base_unit_price' => (float) ($variant['base_unit_price'] ?? $finalPrice),
            'final_price' => $finalPrice,
            'sale_price' => $salePrice,
        ];
    }

    /**
     * Get the delivery info for the product.
     */
    public function deliveryInfos()
    {
        return $this->hasMany(DeliveryInfo::class);
    }

    /**
     * Get the services linked to the product.
     */
    public function services()
    {
        return $this->belongsToMany(Service::class, 'product_service_links')
            ->withPivot('override_price', 'is_enabled')
            ->withTimestamps();
    }

    /**
     * Scope a query to only include active products.
     */
    public function scopeActive($query)
    {
        return $query->where('is_active', true);
    }

    /**
     * Scope a query to only include featured products.
     */
    public function scopeFeatured($query)
    {
        return $query->where('is_featured', true);
    }

    /**
     * Scope a query to only include in-stock products.
     */
    public function scopeInStock($query)
    {
        return $query->where('in_stock', true);
    }

    /**
     * Get the final price (sale price if available, otherwise regular price).
     */
    public function getFinalPriceAttribute()
    {
        return $this->sale_price ?? $this->price;
    }

    /**
     * Check if product is on sale.
     */
    public function getIsOnSaleAttribute()
    {
        return ! is_null($this->sale_price) && $this->sale_price < $this->price;
    }

    /**
     * Get the route key for the model.
     */
    public function getRouteKeyName()
    {
        return 'slug';
    }
}
