<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;

class Coupon extends Model
{
    protected $fillable = [
        'code', 'type', 'value', 'min_amount', 'max_uses', 'used_count',
        'valid_from', 'valid_until', 'is_active', 'description',
        'scope_type', 'scope_ids',
    ];

    protected $casts = [
        'value' => 'decimal:2',
        'min_amount' => 'decimal:2',
        'valid_from' => 'datetime',
        'valid_until' => 'datetime',
        'is_active' => 'boolean',
        'scope_ids' => 'array',
    ];

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

    public function isExhausted(): bool
    {
        if ($this->max_uses === null) {
            return false;
        }
        return $this->used_count >= $this->max_uses;
    }

    public function isValidAt(?\DateTimeInterface $at = null): bool
    {
        $at = $at ?? now();
        if ($this->valid_from && $at < $this->valid_from) {
            return false;
        }
        if ($this->valid_until && $at > $this->valid_until) {
            return false;
        }
        return true;
    }

    public function meetsMinAmount(float $amount): bool
    {
        if ($this->min_amount === null) {
            return true;
        }
        return $amount >= (float) $this->min_amount;
    }

    /**
     * @param  array<int, array{product: \App\Models\Product, qty: int}>  $cartItems
     */
    public function getEligibleSubtotal(array $cartItems): float
    {
        $ids = $this->scope_ids ?? [];
        if ($this->scope_type === 'all' || empty($ids)) {
            return array_sum(array_map(fn ($i) => $i['product']->price * $i['qty'], $cartItems));
        }

        if ($this->scope_type === 'products') {
            $ids = array_map('intval', $ids);
            return array_sum(array_map(function ($item) use ($ids) {
                return in_array((int) $item['product']->id, $ids, true)
                    ? $item['product']->price * $item['qty']
                    : 0;
            }, $cartItems));
        }

        if ($this->scope_type === 'categories') {
            $ids = array_map('intval', $ids);
            $eligibleIds = \App\Models\ProductCategory::whereIn('id', $ids)
                ->get()
                ->flatMap(fn ($c) => $c->getSelfAndDescendantIds())
                ->unique()
                ->values()
                ->all();
            return array_sum(array_map(function ($item) use ($eligibleIds) {
                $catId = $item['product']->product_category_id;
                return $catId && in_array((int) $catId, $eligibleIds, true)
                    ? $item['product']->price * $item['qty']
                    : 0;
            }, $cartItems));
        }

        return 0.0;
    }

    /**
     * @param  array<int, array{product: \App\Models\Product, qty: int}>  $cartItems
     */
    public function calculateDiscount(array $cartItems): float
    {
        $eligibleSubtotal = $this->getEligibleSubtotal($cartItems);
        if ($eligibleSubtotal <= 0 || !$this->meetsMinAmount($eligibleSubtotal)) {
            return 0.0;
        }

        $value = (float) $this->value;
        if ($this->type === 'percent') {
            return round($eligibleSubtotal * ($value / 100), 2);
        }
        return min($value, $eligibleSubtotal);
    }

    public function getLabel(): string
    {
        if ($this->type === 'percent') {
            return (int) $this->value . '% de réduction';
        }
        return number_format((float) $this->value, 2, ',', ' ') . ' € de réduction';
    }
}
