<?php

namespace App\Services;

use App\Models\Promotion;
use App\Models\PromotionUsage;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Cache;

/**
 * Service de gestion des promotions
 */
class PromotionService
{
    /**
     * Appliquer un code promo
     */
    public function applyPromoCode(string $code, float $cartTotal, ?int $userId = null, array $cartItems = []): array
    {
        $promotion = Promotion::byCode($code)->active()->first();

        if (!$promotion) {
            return [
                'success' => false,
                'message' => 'Code promo invalide ou expiré',
                'discount' => 0,
            ];
        }

        if (!$promotion->canBeUsedBy($userId)) {
            return [
                'success' => false,
                'message' => 'Vous avez déjà utilisé ce code promo le maximum de fois autorisé',
                'discount' => 0,
            ];
        }

        if ($promotion->min_purchase && $cartTotal < $promotion->min_purchase) {
            return [
                'success' => false,
                'message' => "Minimum d'achat requis: " . number_format($promotion->min_purchase, 0, ',', ' ') . ' FCFA',
                'discount' => 0,
            ];
        }

        $discount = $promotion->calculateDiscount($cartTotal, $cartItems);

        return [
            'success' => true,
            'message' => 'Code promo appliqué!',
            'discount' => $discount,
            'promotion' => $promotion,
            'new_total' => $cartTotal - $discount,
        ];
    }

    /**
     * Obtenir les ventes flash actives
     */
    public function getActiveFlashSales(): Collection
    {
        return Cache::remember('flash_sales_active', 60, function () {
            return Promotion::active()
                ->flashSales()
                ->orderBy('ends_at')
                ->get();
        });
    }

    /**
     * Obtenir les promotions applicables à un produit
     */
    public function getPromotionsForProduct(int $productId, ?int $categoryId = null): Collection
    {
        return Promotion::active()
            ->where(function ($query) use ($productId, $categoryId) {
                $query->where('applicable_to', Promotion::APPLIES_TO_ALL)
                    ->orWhere(function ($q) use ($productId) {
                        $q->where('applicable_to', Promotion::APPLIES_TO_PRODUCTS)
                            ->whereJsonContains('product_ids', $productId);
                    });

                if ($categoryId) {
                    $query->orWhere(function ($q) use ($categoryId) {
                        $q->where('applicable_to', Promotion::APPLIES_TO_CATEGORIES)
                            ->whereJsonContains('category_ids', $categoryId);
                    });
                }
            })
            ->orderBy('priority', 'desc')
            ->get();
    }

    /**
     * Calculer le meilleur prix avec promotions
     */
    public function getBestPrice(int $productId, float $originalPrice, ?int $categoryId = null): array
    {
        $promotions = $this->getPromotionsForProduct($productId, $categoryId);

        if ($promotions->isEmpty()) {
            return [
                'original_price' => $originalPrice,
                'final_price' => $originalPrice,
                'discount' => 0,
                'promotion' => null,
            ];
        }

        $bestDiscount = 0;
        $bestPromotion = null;

        foreach ($promotions as $promotion) {
            $discount = $promotion->calculateDiscount($originalPrice);
            
            if ($discount > $bestDiscount) {
                $bestDiscount = $discount;
                $bestPromotion = $promotion;
            }
        }

        return [
            'original_price' => $originalPrice,
            'final_price' => $originalPrice - $bestDiscount,
            'discount' => $bestDiscount,
            'discount_percentage' => $originalPrice > 0 ? round(($bestDiscount / $originalPrice) * 100) : 0,
            'promotion' => $bestPromotion,
        ];
    }

    /**
     * Créer une vente flash
     */
    public function createFlashSale(array $data): Promotion
    {
        return Promotion::create([
            'name' => $data['name'],
            'description' => $data['description'] ?? null,
            'type' => Promotion::TYPE_FLASH_SALE,
            'value' => $data['discount_percentage'],
            'starts_at' => $data['starts_at'],
            'ends_at' => $data['ends_at'],
            'is_active' => true,
            'applicable_to' => $data['applicable_to'] ?? Promotion::APPLIES_TO_ALL,
            'product_ids' => $data['product_ids'] ?? null,
            'category_ids' => $data['category_ids'] ?? null,
            'priority' => 100, // Haute priorité pour les flash sales
        ]);
    }

    /**
     * Créer un code promo
     */
    public function createPromoCode(array $data): Promotion
    {
        return Promotion::create([
            'name' => $data['name'],
            'code' => strtoupper($data['code']),
            'description' => $data['description'] ?? null,
            'type' => $data['type'] ?? Promotion::TYPE_PERCENTAGE,
            'value' => $data['value'],
            'min_purchase' => $data['min_purchase'] ?? null,
            'max_discount' => $data['max_discount'] ?? null,
            'usage_limit' => $data['usage_limit'] ?? null,
            'user_limit' => $data['user_limit'] ?? 1,
            'starts_at' => $data['starts_at'] ?? now(),
            'ends_at' => $data['ends_at'] ?? null,
            'is_active' => true,
            'applicable_to' => $data['applicable_to'] ?? Promotion::APPLIES_TO_ALL,
            'product_ids' => $data['product_ids'] ?? null,
            'category_ids' => $data['category_ids'] ?? null,
            'user_ids' => $data['user_ids'] ?? null,
            'priority' => $data['priority'] ?? 10,
        ]);
    }

    /**
     * Enregistrer l'utilisation d'une promotion
     */
    public function recordUsage(Promotion $promotion, int $userId, ?int $orderId = null, float $discountAmount = 0): void
    {
        PromotionUsage::create([
            'promotion_id' => $promotion->id,
            'user_id' => $userId,
            'order_id' => $orderId,
            'discount_amount' => $discountAmount,
            'used_at' => now(),
        ]);

        $promotion->increment('usage_count');

        // Invalider le cache
        Cache::forget('flash_sales_active');
    }

    /**
     * Statistiques des promotions
     */
    public function getStats(): array
    {
        return Cache::remember('promotion_stats', 300, function () {
            $promotions = Promotion::withCount('usages')
                ->withSum('usages', 'discount_amount')
                ->get();

            return [
                'total_promotions' => $promotions->count(),
                'active_promotions' => Promotion::active()->count(),
                'total_usages' => $promotions->sum('usages_count'),
                'total_discounts_given' => $promotions->sum('usages_sum_discount_amount') ?? 0,
                'most_used' => $promotions->sortByDesc('usages_count')->first(),
                'flash_sales_count' => Promotion::active()->flashSales()->count(),
            ];
        });
    }

    /**
     * Obtenir les promotions proches de l'expiration
     */
    public function getExpiringPromotions(int $hours = 24): Collection
    {
        return Promotion::active()
            ->where('ends_at', '<=', now()->addHours($hours))
            ->orderBy('ends_at')
            ->get();
    }

    /**
     * Générer un code promo unique
     */
    public function generateUniqueCode(int $length = 8): string
    {
        $characters = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
        
        do {
            $code = '';
            for ($i = 0; $i < $length; $i++) {
                $code .= $characters[random_int(0, strlen($characters) - 1)];
            }
        } while (Promotion::where('code', $code)->exists());

        return $code;
    }
}
