<?php

namespace App\Services;

use App\Models\User;
use App\Models\Order;
use App\Models\LoyaltyPoint;
use App\Models\Setting;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

class LoyaltyService
{
    public function earnPoints(User $user, $amount, $source, $orderId = null, $description = null)
    {
        $pointsPerCurrency = floatval(Setting::get('loyalty_points_per_currency', 1));
        $points = floor($amount / $pointsPerCurrency);

        if ($points <= 0) {
            return null;
        }

        $expiresAt = null;
        $expirationMonths = intval(Setting::get('loyalty_points_expiration_months', 12));
        if ($expirationMonths > 0) {
            $expiresAt = now()->addMonths($expirationMonths);
        }

        $loyaltyPoint = LoyaltyPoint::create([
            'user_id' => $user->id,
            'points' => $points,
            'type' => 'earned',
            'source' => $source,
            'order_id' => $orderId,
            'description' => $description ?? "Points gagnés pour achat de {$amount}",
            'expires_at' => $expiresAt,
        ]);

        $user->increment('total_loyalty_points', $points);

        Log::info('Points de fidélité gagnés', [
            'user_id' => $user->id,
            'points' => $points,
            'source' => $source,
        ]);

        return $loyaltyPoint;
    }

    public function spendPoints(User $user, $points, $description = null)
    {
        $availablePoints = $this->getAvailablePoints($user);

        if ($availablePoints < $points) {
            throw new \Exception('Points insuffisants');
        }

        $loyaltyPoint = LoyaltyPoint::create([
            'user_id' => $user->id,
            'points' => -$points,
            'type' => 'spent',
            'description' => $description,
        ]);

        $user->decrement('total_loyalty_points', $points);

        Log::info('Points de fidélité dépensés', [
            'user_id' => $user->id,
            'points' => $points,
        ]);

        return $loyaltyPoint;
    }

    public function getAvailablePoints(User $user)
    {
        $earned = LoyaltyPoint::where('user_id', $user->id)
            ->where('type', 'earned')
            ->valid()
            ->sum('points');

        $spent = LoyaltyPoint::where('user_id', $user->id)
            ->where('type', 'spent')
            ->sum('points');

        return max(0, $earned + $spent);
    }

    public function getPointsValue($points)
    {
        $pointValue = floatval(Setting::get('loyalty_point_value', 1));
        return $points * $pointValue;
    }

    public function convertPointsToDiscount(User $user, $points)
    {
        $availablePoints = $this->getAvailablePoints($user);

        if ($points > $availablePoints) {
            throw new \Exception('Points insuffisants');
        }

        $discountValue = $this->getPointsValue($points);

        $this->spendPoints($user, $points, "Conversion en réduction de {$discountValue}");

        return $discountValue;
    }

    public function awardBonusPoints(User $user, $points, $reason)
    {
        $loyaltyPoint = LoyaltyPoint::create([
            'user_id' => $user->id,
            'points' => $points,
            'type' => 'bonus',
            'source' => 'bonus',
            'description' => $reason,
        ]);

        $user->increment('total_loyalty_points', $points);

        Log::info('Points bonus attribués', [
            'user_id' => $user->id,
            'points' => $points,
            'reason' => $reason,
        ]);

        return $loyaltyPoint;
    }

    public function expireOldPoints()
    {
        $expiredPoints = LoyaltyPoint::where('type', 'earned')
            ->whereNotNull('expires_at')
            ->where('expires_at', '<', now())
            ->get();

        foreach ($expiredPoints as $point) {
            LoyaltyPoint::create([
                'user_id' => $point->user_id,
                'points' => -$point->points,
                'type' => 'expired',
                'description' => 'Points expirés',
            ]);

            $user = User::find($point->user_id);
            if ($user) {
                $user->decrement('total_loyalty_points', $point->points);
            }
        }

        Log::info('Points expirés traités', ['count' => $expiredPoints->count()]);

        return $expiredPoints->count();
    }

    public function getPointsHistory(User $user, $limit = 20)
    {
        return LoyaltyPoint::where('user_id', $user->id)
            ->orderBy('created_at', 'desc')
            ->limit($limit)
            ->get();
    }

    public function getUserTier(User $user)
    {
        $totalPoints = $user->total_loyalty_points;
        
        $tiers = [
            ['name' => 'Bronze', 'min_points' => 0, 'multiplier' => 1],
            ['name' => 'Argent', 'min_points' => 1000, 'multiplier' => 1.25],
            ['name' => 'Or', 'min_points' => 5000, 'multiplier' => 1.5],
            ['name' => 'Platine', 'min_points' => 15000, 'multiplier' => 2],
            ['name' => 'Diamant', 'min_points' => 50000, 'multiplier' => 3],
        ];

        $currentTier = $tiers[0];
        foreach ($tiers as $tier) {
            if ($totalPoints >= $tier['min_points']) {
                $currentTier = $tier;
            }
        }

        return $currentTier;
    }
}
