<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Str;

class Product extends Model
{
    protected $fillable = [
        'shop_id',
        'product_title',
        'price',
        'offer_price',
        'offer_expiry_date',
        'stock',
        'sku',
        'feature_image',
        'attributes',
        'created_by',
    ];

    protected $casts = [
        'attributes' => 'array',
        'price' => 'decimal:2',
        'offer_price' => 'decimal:2',
        'offer_expiry_date' => 'datetime',
    ];

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

    public function creator(): BelongsTo
    {
        return $this->belongsTo(User::class, 'created_by');
    }

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

    public function scopeAvailable(Builder $query): Builder
    {
        return $query->where('stock', '>', 0);
    }

    public function isInStock(): bool
    {
        return $this->totalAvailableStock() > 0;
    }

    public function totalAvailableStock(): int
    {
        $variantInventory = $this->variantInventory();

        if ($variantInventory !== []) {
            return (int) collect($variantInventory)->sum('stock');
        }

        return (int) $this->stock;
    }

    public function hasVariantInventory(): bool
    {
        return $this->variantInventory() !== [];
    }

    public function variantInventory(): array
    {
        $attributes = $this->getAttribute('attributes');
        $inventory = is_array($attributes) ? ($attributes['_variant_inventory'] ?? []) : [];

        if (! is_array($inventory)) {
            return [];
        }

        $normalized = [];
        $usedKeys = [];

        foreach ($inventory as $item) {
            if (! is_array($item)) {
                continue;
            }

            $label = trim((string) ($item['label'] ?? $item['name'] ?? $item['value'] ?? ''));
            if ($label === '') {
                continue;
            }

            $keyBase = Str::slug($label);
            if ($keyBase === '') {
                $keyBase = 'variant';
            }

            $key = $keyBase;
            $suffix = 2;
            while (in_array($key, $usedKeys, true)) {
                $key = $keyBase . '-' . $suffix;
                $suffix++;
            }

            $usedKeys[] = $key;

            $stock = max(0, (int) ($item['stock'] ?? 0));

            $normalized[] = [
                'key' => $key,
                'label' => $label,
                'stock' => $stock,
                'is_available' => $stock > 0,
            ];
        }

        return $normalized;
    }

    public function findVariantOption(?string $variantLabel): ?array
    {
        $needle = trim((string) $variantLabel);
        if ($needle === '') {
            return null;
        }

        foreach ($this->variantInventory() as $variant) {
            if (strcasecmp($variant['label'], $needle) === 0 || strcasecmp($variant['key'], $needle) === 0) {
                return $variant;
            }
        }

        return null;
    }

    public function decrementVariantStock(string $variantLabel, int $quantity): bool
    {
        $quantity = max(0, $quantity);
        if ($quantity < 1) {
            return false;
        }

        $attributes = $this->getAttribute('attributes');
        if (! is_array($attributes) || ! isset($attributes['_variant_inventory']) || ! is_array($attributes['_variant_inventory'])) {
            return false;
        }

        $updated = false;
        foreach ($attributes['_variant_inventory'] as &$item) {
            if (! is_array($item)) {
                continue;
            }

            $label = trim((string) ($item['label'] ?? $item['name'] ?? $item['value'] ?? ''));
            if ($label === '' || strcasecmp($label, $variantLabel) !== 0) {
                continue;
            }

            $item['label'] = $label;
            $item['stock'] = max(0, (int) ($item['stock'] ?? 0) - $quantity);
            $updated = true;
            break;
        }
        unset($item);

        if (! $updated) {
            return false;
        }

        $aggregateStock = collect($attributes['_variant_inventory'])
            ->filter(fn($item) => is_array($item))
            ->sum(fn($item) => max(0, (int) ($item['stock'] ?? 0)));

        $this->forceFill([
            'attributes' => $attributes,
            'stock' => (int) $aggregateStock,
        ])->save();

        return true;
    }

    public function displayAttributes(): array
    {
        $attributes = $this->getAttribute('attributes');

        if (! is_array($attributes)) {
            return [];
        }

        unset($attributes['_variant_inventory']);

        return $attributes;
    }
}
