<?php

namespace App\Models;

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

class Coupon extends Model
{
    use HasFactory;

    // Scopes disponibles
    const SCOPE_ALL = 'all';
    const SCOPE_SHOP_ONLY = 'shop_only';
    const SCOPE_INVESTMENT_ONLY = 'investment_only';
    const SCOPE_CATEGORY = 'category';
    const SCOPE_PRODUCT = 'product';
    const SCOPE_SELLER = 'seller';
    const SCOPE_SELLER_OWN = 'seller_own';

    protected $fillable = [
        'code',
        'name',
        'description',
        'type',
        'value',
        'min_order_amount',
        'max_discount',
        'usage_limit',
        'usage_count',
        'usage_per_user',
        'starts_at',
        'expires_at',
        'is_active',
        'seller_id',
        'applicable_categories',
        'applicable_products',
        'applicable_sellers',
        'scope',
        'created_by_type',
        'admin_id',
        'includes_free_shipping',
    ];

    protected $casts = [
        'value' => 'decimal:2',
        'min_order_amount' => 'decimal:2',
        'max_discount' => 'decimal:2',
        'applicable_categories' => 'array',
        'applicable_products' => 'array',
        'applicable_sellers' => 'array',
        'starts_at' => 'datetime',
        'expires_at' => 'datetime',
        'is_active' => 'boolean',
        'includes_free_shipping' => 'boolean',
    ];

    public function seller()
    {
        return $this->belongsTo(Seller::class);
    }

    public function admin()
    {
        return $this->belongsTo(User::class, 'admin_id');
    }

    public function scopeActive($query)
    {
        return $query->where('is_active', true);
    }

    public function scopeValid($query)
    {
        return $query->where('is_active', true)
            ->where(function ($q) {
                $q->whereNull('starts_at')->orWhere('starts_at', '<=', now());
            })
            ->where(function ($q) {
                $q->whereNull('expires_at')->orWhere('expires_at', '>', now());
            })
            ->where(function ($q) {
                $q->whereNull('usage_limit')->orWhereColumn('usage_count', '<', 'usage_limit');
            });
    }

    public function scopeAdminCoupons($query)
    {
        return $query->where('created_by_type', 'admin');
    }

    public function scopeSellerCoupons($query)
    {
        return $query->where('created_by_type', 'seller');
    }

    /**
     * Vérifie si le coupon est valide (dates, limite d'usage, actif)
     */
    public function isValid(): bool
    {
        if (!$this->is_active) return false;
        if ($this->starts_at && $this->starts_at > now()) return false;
        if ($this->expires_at && $this->expires_at < now()) return false;
        if ($this->usage_limit && $this->usage_count >= $this->usage_limit) return false;
        return true;
    }

    /**
     * Vérifie si le coupon est applicable à un produit spécifique
     */
    public function isApplicableToProduct($product): bool
    {
        if (!$this->isValid()) return false;

        // Coupon admin avec scope 'all' - applicable partout
        if ($this->created_by_type === 'admin' && $this->scope === self::SCOPE_ALL) {
            return true;
        }

        // Coupon admin pour investissement uniquement
        if ($this->created_by_type === 'admin' && $this->scope === self::SCOPE_INVESTMENT_ONLY) {
            return $product->is_investment ?? false;
        }

        // Coupon admin pour boutique uniquement
        if ($this->created_by_type === 'admin' && $this->scope === self::SCOPE_SHOP_ONLY) {
            return !($product->is_investment ?? false);
        }

        // Coupon avec scope 'category'
        if ($this->scope === self::SCOPE_CATEGORY) {
            $categories = $this->applicable_categories ?? [];
            return in_array($product->category_id, $categories);
        }

        // Coupon avec scope 'product'
        if ($this->scope === self::SCOPE_PRODUCT) {
            $products = $this->applicable_products ?? [];
            return in_array($product->id, $products);
        }

        // Coupon avec scope 'seller' (admin créé pour des vendeurs spécifiques)
        if ($this->scope === self::SCOPE_SELLER) {
            $sellers = $this->applicable_sellers ?? [];
            return $product->seller_id && in_array($product->seller_id, $sellers);
        }

        // Coupon vendeur - uniquement pour ses propres produits
        if ($this->created_by_type === 'seller' && $this->scope === self::SCOPE_SELLER_OWN) {
            return $product->seller_id === $this->seller_id;
        }

        return false;
    }

    /**
     * Vérifie si le coupon est applicable à un panier complet
     * Retourne les items applicables et ceux qui ne le sont pas
     */
    public function getApplicableCartItems(array $cartItems): array
    {
        $applicable = [];
        $nonApplicable = [];

        foreach ($cartItems as $item) {
            $product = $item['product'] ?? Product::find($item['product_id'] ?? null);
            if ($product && $this->isApplicableToProduct($product)) {
                $applicable[] = $item;
            } else {
                $nonApplicable[] = $item;
            }
        }

        return [
            'applicable' => $applicable,
            'non_applicable' => $nonApplicable,
            'has_applicable' => count($applicable) > 0
        ];
    }

    /**
     * Calcule la réduction en fonction du type et des montants
     */
    public function calculateDiscount(float $orderTotal, float $shippingCost = 0): array
    {
        $result = [
            'discount' => 0,
            'shipping_discount' => 0,
            'total_discount' => 0,
            'reason' => null
        ];

        // Vérifier le montant minimum
        if ($orderTotal < $this->min_order_amount) {
            $result['reason'] = "Montant minimum requis: " . number_format($this->min_order_amount, 0, ',', ' ') . " FCFA";
            return $result;
        }

        $discount = 0;

        switch ($this->type) {
            case 'percentage':
                $discount = ($orderTotal * $this->value) / 100;
                break;
            case 'fixed':
                $discount = $this->value;
                break;
            case 'free_shipping':
                $result['shipping_discount'] = $shippingCost;
                $result['total_discount'] = $shippingCost;
                return $result;
        }

        // Appliquer le maximum de réduction si défini
        if ($this->max_discount && $discount > $this->max_discount) {
            $discount = $this->max_discount;
        }

        // La réduction ne peut pas dépasser le total de la commande
        $discount = min($discount, $orderTotal);

        $result['discount'] = $discount;

        // Ajouter la livraison gratuite si incluse
        if ($this->includes_free_shipping) {
            $result['shipping_discount'] = $shippingCost;
        }

        $result['total_discount'] = $result['discount'] + $result['shipping_discount'];

        return $result;
    }

    /**
     * Calcul complet pour un panier avec vérification d'applicabilité
     */
    public function calculateCartDiscount(array $cartItems, float $shippingCost = 0): array
    {
        $applicableCheck = $this->getApplicableCartItems($cartItems);
        
        if (!$applicableCheck['has_applicable']) {
            return [
                'success' => false,
                'discount' => 0,
                'shipping_discount' => 0,
                'total_discount' => 0,
                'message' => 'Ce coupon n\'est pas applicable aux produits de votre panier.',
                'applicable_items' => [],
                'non_applicable_items' => $applicableCheck['non_applicable']
            ];
        }

        // Calculer le total des items applicables
        $applicableTotal = 0;
        foreach ($applicableCheck['applicable'] as $item) {
            $applicableTotal += ($item['price'] ?? 0) * ($item['quantity'] ?? 1);
        }

        $discountResult = $this->calculateDiscount($applicableTotal, $shippingCost);

        if ($discountResult['reason']) {
            return [
                'success' => false,
                'discount' => 0,
                'shipping_discount' => 0,
                'total_discount' => 0,
                'message' => $discountResult['reason'],
                'applicable_items' => $applicableCheck['applicable'],
                'non_applicable_items' => $applicableCheck['non_applicable']
            ];
        }

        return [
            'success' => true,
            'discount' => $discountResult['discount'],
            'shipping_discount' => $discountResult['shipping_discount'],
            'total_discount' => $discountResult['total_discount'],
            'message' => $this->getDiscountMessage($discountResult),
            'applicable_items' => $applicableCheck['applicable'],
            'non_applicable_items' => $applicableCheck['non_applicable']
        ];
    }

    /**
     * Génère un message descriptif de la réduction
     */
    private function getDiscountMessage(array $discountResult): string
    {
        $parts = [];

        if ($discountResult['discount'] > 0) {
            $parts[] = '-' . number_format($discountResult['discount'], 0, ',', ' ') . ' FCFA';
        }

        if ($discountResult['shipping_discount'] > 0) {
            $parts[] = 'Livraison gratuite';
        }

        return implode(' + ', $parts);
    }

    public function incrementUsage()
    {
        $this->increment('usage_count');
    }

    /**
     * Vérifie si un utilisateur a déjà atteint sa limite d'utilisation
     */
    public function hasUserReachedLimit(int $userId): bool
    {
        if (!$this->usage_per_user) return false;

        $usageCount = \DB::table('coupon_usages')
            ->where('coupon_id', $this->id)
            ->where('user_id', $userId)
            ->count();

        return $usageCount >= $this->usage_per_user;
    }

    /**
     * Enregistre l'utilisation du coupon par un utilisateur
     */
    public function recordUsage(int $userId, int $orderId, float $discountAmount)
    {
        \DB::table('coupon_usages')->insert([
            'coupon_id' => $this->id,
            'user_id' => $userId,
            'order_id' => $orderId,
            'discount_amount' => $discountAmount,
            'created_at' => now(),
        ]);

        $this->incrementUsage();
    }
}
