<?php

namespace App\Models;

use App\Enums\ProductStatus;
use App\Enums\ReviewStatus;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Carbon;

class Product extends Model
{
    use HasFactory, SoftDeletes;

    protected $fillable = [
        'category_id',
        'brand_id',
        'name',
        'slug',
        'sku',
        'barcode',
        'short_description',
        'description',
        'specifications',
        'original_price',
        'sale_price',
        'status',
        'is_featured',
        'is_trending',
        'is_new_arrival',
        'is_flash_sale',
        'flash_sale_starts_at',
        'flash_sale_ends_at',
        'meta_title',
        'meta_description',
    ];

    protected function casts(): array
    {
        return [
            'status' => ProductStatus::class,
            'specifications' => 'array',
            'original_price' => 'decimal:2',
            'sale_price' => 'decimal:2',
            'is_featured' => 'boolean',
            'is_trending' => 'boolean',
            'is_new_arrival' => 'boolean',
            'is_flash_sale' => 'boolean',
            'flash_sale_starts_at' => 'datetime',
            'flash_sale_ends_at' => 'datetime',
        ];
    }

    // ---------------------------------------------------------------
    // Relationships
    // ---------------------------------------------------------------

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

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

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

    public function primaryImage(): HasOne
    {
        return $this->hasOne(ProductImage::class)->where('is_primary', true);
    }

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

    public function tags(): BelongsToMany
    {
        return $this->belongsToMany(Tag::class, 'product_tag');
    }

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

    /** Direct FK on order_items (kept even if the variant is later deleted) — powers data-driven "Best Sellers". */
    public function orderItems(): HasMany
    {
        return $this->hasMany(OrderItem::class);
    }

    public function approvedReviews(): HasMany
    {
        return $this->reviews()->where('status', ReviewStatus::Approved);
    }

    // ---------------------------------------------------------------
    // Accessors
    // ---------------------------------------------------------------

    protected function isOnSale(): Attribute
    {
        return Attribute::get(fn () => $this->sale_price !== null && (float) $this->sale_price < (float) $this->original_price
        );
    }

    protected function currentPrice(): Attribute
    {
        return Attribute::get(fn () => $this->is_on_sale ? $this->sale_price : $this->original_price
        );
    }

    protected function discountPercentage(): Attribute
    {
        return Attribute::get(function () {
            if (! $this->is_on_sale) {
                return 0;
            }

            return (int) round((1 - ((float) $this->sale_price / (float) $this->original_price)) * 100);
        });
    }

    protected function isFlashSaleLive(): Attribute
    {
        return Attribute::get(function () {
            if (! $this->is_flash_sale) {
                return false;
            }

            $now = Carbon::now();

            if ($this->flash_sale_starts_at && $now->lt($this->flash_sale_starts_at)) {
                return false;
            }

            if ($this->flash_sale_ends_at && $now->gt($this->flash_sale_ends_at)) {
                return false;
            }

            return true;
        });
    }

    /** Total stock across every variant — used for the listing-level "in stock" badge. */
    protected function totalStock(): Attribute
    {
        return Attribute::get(fn () => $this->variants->sum(
            fn (ProductVariant $variant) => $variant->inventory?->available_quantity ?? 0
        ));
    }

    protected function isInStock(): Attribute
    {
        return Attribute::get(fn () => $this->total_stock > 0);
    }

    // ---------------------------------------------------------------
    // Scopes
    // ---------------------------------------------------------------

    public function scopeActive(Builder $query): void
    {
        $query->where('status', ProductStatus::Active);
    }

    public function scopeFeatured(Builder $query): void
    {
        $query->where('is_featured', true);
    }

    public function scopeTrending(Builder $query): void
    {
        $query->where('is_trending', true);
    }

    public function scopeNewArrival(Builder $query): void
    {
        $query->where('is_new_arrival', true);
    }

    public function scopeFlashSale(Builder $query): void
    {
        $query->where('is_flash_sale', true)
            ->where(fn (Builder $q) => $q->whereNull('flash_sale_starts_at')->orWhere('flash_sale_starts_at', '<=', now()))
            ->where(fn (Builder $q) => $q->whereNull('flash_sale_ends_at')->orWhere('flash_sale_ends_at', '>=', now()));
    }

    public function scopeInStock(Builder $query): void
    {
        $query->whereHas('variants.inventory', fn (Builder $q) => $q->whereColumn('quantity', '>', 'reserved_quantity')
        );
    }

    public function scopeSearch(Builder $query, string $term): void
    {
        $query->where(fn (Builder $q) => $q->where('name', 'like', "%{$term}%")
            ->orWhere('sku', 'like', "%{$term}%")
            ->orWhere('short_description', 'like', "%{$term}%")
        );
    }

    /**
     * Adds `reviews_avg_rating` / `reviews_count` (approved reviews only) to
     * each result via a single SQL aggregate — not cached columns, so the
     * rating shown on listing cards is always current the moment a review
     * is approved, without an N+1 query per card.
     */
    public function scopeWithRatings(Builder $query): Builder
    {
        return $query
            ->withAvg('approvedReviews as reviews_avg_rating', 'rating')
            ->withCount('approvedReviews as reviews_count');
    }

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