<?php

namespace App\Services;

use App\Models\User;
use App\Models\Order;
use App\Models\Commission;
use App\Models\Referral;
use App\Models\Setting;
use App\Models\MlmLevel;
use App\Models\Rank;
use App\Models\Wallet;
use App\Services\AMMService;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\DB;

class MLMService
{
    protected $maxLevels = 2;
    protected $walletService;
    protected $ammService;

    public function __construct()
    {
        $this->maxLevels = intval(Setting::get('mlm_max_levels', 2));
        $this->walletService = new WalletService();
        $this->ammService = new AMMService();
    }

    public function generateMemberCode($name)
    {
        $prefix = strtoupper(substr(str_replace(' ', '', $name), 0, 3));
        $randomNumber = rand(100, 999);
        $code = $prefix . $randomNumber;

        while (User::where('member_code', $code)->exists()) {
            $randomNumber = rand(100, 999);
            $code = $prefix . $randomNumber;
        }

        return $code;
    }

    public function generateReferralCode()
    {
        do {
            $code = strtoupper(Str::random(8));
        } while (User::where('referral_code', $code)->exists());

        return $code;
    }

    public function calculateCommissions(Order $order)
    {
        $user = $order->user;
        
        if (!$user || !$user->sponsor_id) {
            Log::info('Aucun sponsor trouvé pour la commande', ['order_id' => $order->id]);
            return [];
        }

        $commissionsCreated = [];
        $currentSponsor = User::find($user->sponsor_id);
        $level = 1;

        Log::info('Calcul des commissions MLM (2 niveaux)', [
            'order_id' => $order->id,
            'user_id' => $user->id,
            'max_levels' => $this->maxLevels
        ]);

        while ($currentSponsor && $level <= $this->maxLevels) {
            $rate = $this->getCommissionRate($level);

            if ($rate > 0 && $currentSponsor->is_active && $this->canReceiveCommissions($currentSponsor)) {
                $commissionAmount = ($order->total_amount * $rate) / 100;

                if ($commissionAmount > 0) {
                    $commission = $this->createCommission(
                        $currentSponsor,
                        $order,
                        $user,
                        $level,
                        $commissionAmount
                    );

                    $commissionsCreated[] = $commission;

                    $this->creditWallet($currentSponsor, $commissionAmount, $commission);

                    $this->sendCommissionNotification($currentSponsor, $user, $order, $level, $commissionAmount);
                }
            }

            $currentSponsor = $currentSponsor->sponsor_id ? User::find($currentSponsor->sponsor_id) : null;
            $level++;
        }

        Log::info('Commissions créées', [
            'order_id' => $order->id,
            'count' => count($commissionsCreated)
        ]);

        return $commissionsCreated;
    }

    protected function getCommissionRate($level)
    {
        // ÉTAPE 4: Source unique - utiliser UNIQUEMENT mlm_levels table
        // Cela élimine les problèmes de cache et assure les valeurs sont toujours à jour
        if ($level > $this->maxLevels) {
            return 0;
        }

        // Lire DIRECTEMENT depuis mlm_levels (pas de cache, pas de settings)
        $mlmLevel = MlmLevel::where('level', $level)
            ->where('is_active', true)
            ->first();
        
        if ($mlmLevel) {
            return floatval($mlmLevel->commission_rate);
        }

        // Fallback: taux par défaut si niveau n'existe pas
        $defaultRates = [
            1 => 10,
            2 => 5
        ];

        return floatval($defaultRates[$level] ?? 0);
    }

    protected function canReceiveCommissions(User $user)
    {
        // Règle 1: is_active est REQUIS (sponsor doit être actif)
        if (!$user->is_active) {
            Log::debug('Sponsor inactif - pas de commission', ['user_id' => $user->id]);
            return false;
        }

        // Règle 2: subscription_paid OU has_paid_investment_product est REQUIS
        // (Le sponsor doit avoir payé son abonnement OU son produit d'investissement)
        $hasPaidSubscription = $user->subscription_paid ?? false;
        $hasPaidInvestment = $user->has_paid_investment_product ?? false;
        
        if (!$hasPaidSubscription && !$hasPaidInvestment) {
            Log::debug('Sponsor non abonné et pas de produit d\'investissement payé - pas de commission', ['user_id' => $user->id]);
            return false;
        }

        // Règle 3: Vérifier l'AMM (Achat Mensuel Minimum) via le service
        // L'AMM est actif si : exonéré OU progression complète OU avance payée
        $enableAmmChecking = Setting::get('enable_amm_checking', true);
        
        if ($enableAmmChecking && !$this->ammService->canReceiveCommission($user)) {
            Log::warning('Sponsor bloqué par AMM non atteint', [
                'user_id' => $user->id,
                'amm_status' => $this->ammService->getAmmStatus($user)
            ]);
            return false;
        }

        // Règle 4: require_monthly_purchase (ancienne règle basée sur 30 jours)
        // Cette règle est maintenant remplacée par l'AMM mais gardée pour compatibilité
        $requireMonthlyPurchase = Setting::get('require_monthly_purchase', false);
        
        if ($requireMonthlyPurchase && $user->last_purchase_date) {
            $daysSinceLastPurchase = now()->diffInDays($user->last_purchase_date);
            if ($daysSinceLastPurchase > 30) {
                Log::warning('Sponsor bloqué par règle 30 jours', [
                    'user_id' => $user->id,
                    'last_purchase' => $user->last_purchase_date
                ]);
                return false;
            }
        }

        return true;
    }

    protected function createCommission(User $sponsor, Order $order, User $buyer, $level, $amount)
    {
        // Type basé sur le niveau: level1 pour N1 (direct), level2 pour N2 (indirect)
        $type = $level === 1 ? 'level1' : 'level2';
        $typeLabel = $level === 1 ? 'Commission directe (N1)' : 'Commission indirecte (N2)';
        
        // Vérifier si la commission doit être mise en attente (début de mois)
        $initialStatus = $this->ammService->getInitialCommissionStatus($sponsor, $buyer);
        $description = "{$typeLabel} de {$buyer->name} - Commande #{$order->order_number}";
        
        if ($initialStatus === 'held') {
            $description .= ' [En attente - vérification AMM le 3]';
        }
        
        return Commission::create([
            'user_id' => $sponsor->id,
            'order_id' => $order->id,
            'from_user_id' => $buyer->id,
            'type' => $type,
            'level' => $level,
            'amount' => $amount,
            'status' => $initialStatus,
            'description' => $description
        ]);
    }

    protected function creditWallet(User $user, $amount, Commission $commission)
    {
        // Si la commission est en attente (held), ne pas créditer maintenant
        // Elle sera créditée le 3ème jour du mois par la commande ProcessHeldCommissions
        if ($commission->status === 'held') {
            Log::info('Commission mise en attente - crédit différé au 3ème jour du mois', [
                'commission_id' => $commission->id,
                'user_id' => $user->id,
                'amount' => $amount,
            ]);
            return;
        }
        
        try {
            // Description claire pour la transaction selon le type
            if ($commission->type === 'rank_bonus') {
                $description = $commission->description ?? 'Prime de rang';
            } else {
                $typeLabel = $commission->level === 1 ? 'Commission directe (N1)' : 'Commission indirecte (N2)';
                $fromUser = User::find($commission->from_user_id);
                $fromUserName = $fromUser ? $fromUser->name : 'Membre';
                $description = "{$typeLabel} - Achat de {$fromUserName}";
            }
            
            $this->walletService->credit(
                $user,
                $amount,
                'commission',
                $description,
                [
                    'commission_id' => $commission->id,
                    'commission_type' => $commission->type,
                    'commission_level' => $commission->level,
                    'from_user_id' => $commission->from_user_id,
                    'order_id' => $commission->order_id
                ]
            );
            
            // Mettre à jour le statut de la commission à approved
            $commission->update(['status' => 'approved']);
            
            Log::info('Commission créditée au wallet', [
                'user_id' => $user->id,
                'user_name' => $user->name,
                'amount' => $amount,
                'level' => $commission->level,
                'type' => $commission->type
            ]);
            
        } catch (\Exception $e) {
            Log::error('Erreur crédit wallet commission: ' . $e->getMessage());
            // Fallback: incrémenter directement les champs
            $user->increment('total_commissions', $amount);
            $user->increment('available_balance', $amount);
        }
    }

    protected function sendCommissionNotification(User $sponsor, User $buyer, Order $order, $level, $amount)
    {
        try {
            if (class_exists('App\Services\EmailService')) {
                EmailService::sendCommissionNotification($sponsor->email, [
                    'member_name' => $sponsor->name,
                    'commission_amount' => number_format($amount, 0, ',', ' '),
                    'commission_level' => "Niveau {$level}",
                    'buyer_name' => $buyer->name,
                    'order_number' => $order->order_number,
                    'commission_date' => now()->format('d/m/Y à H:i')
                ]);
            }
        } catch (\Exception $e) {
            Log::error("Erreur envoi email commission niveau {$level}: " . $e->getMessage());
        }
    }

    public function giveQuickStartBonus(User $user)
    {
        $bonusAmount = floatval(Setting::get('quick_start_bonus', 5000));

        if ($user->sponsor_id) {
            $sponsor = User::find($user->sponsor_id);
            
            if ($sponsor && $sponsor->is_active && $this->canReceiveCommissions($sponsor)) {
                $commission = Commission::create([
                    'user_id' => $sponsor->id,
                    'order_id' => null,
                    'from_user_id' => $user->id,
                    'type' => 'quick_start',
                    'level' => 1,
                    'amount' => $bonusAmount,
                    'status' => 'pending',
                    'description' => "Bonus de démarrage rapide pour {$user->name}"
                ]);

                $this->creditWallet($sponsor, $bonusAmount, $commission);

                Log::info('Bonus démarrage rapide attribué', [
                    'sponsor_id' => $sponsor->id,
                    'new_member_id' => $user->id,
                    'bonus_amount' => $bonusAmount
                ]);

                return $commission;
            }
        }

        return null;
    }

    public function createReferralRelationship(User $referred, User $sponsor)
    {
        $currentSponsor = $sponsor;
        $level = 1;

        while ($currentSponsor && $level <= $this->maxLevels) {
            Referral::updateOrCreate(
                [
                    'sponsor_id' => $currentSponsor->id,
                    'referred_id' => $referred->id,
                ],
                [
                    'level' => $level,
                    'is_active' => true
                ]
            );

            $currentSponsor = $currentSponsor->sponsor_id ? User::find($currentSponsor->sponsor_id) : null;
            $level++;
        }

        Log::info('Relations de parrainage créées (2 niveaux)', [
            'sponsor_id' => $sponsor->id,
            'referred_id' => $referred->id,
            'levels_created' => min($level - 1, $this->maxLevels)
        ]);
    }

    public function checkUserActivity(User $user)
    {
        $daysAllowed = intval(Setting::get('inactivity_days_limit', 30));
        
        if ($user->last_purchase_date) {
            $daysSinceLastPurchase = now()->diffInDays($user->last_purchase_date);
            
            if ($daysSinceLastPurchase > $daysAllowed) {
                $user->update(['is_active' => false]);

                Log::info('Utilisateur désactivé pour inactivité', [
                    'user_id' => $user->id,
                    'last_purchase' => $user->last_purchase_date,
                    'days_since_purchase' => $daysSinceLastPurchase
                ]);

                return false;
            }
        }

        return true;
    }

    public function reactivateUser(User $user)
    {
        $user->update([
            'is_active' => true,
            'last_purchase_date' => now()
        ]);

        Log::info('Utilisateur réactivé', ['user_id' => $user->id]);
    }

    public function getUserNetworkTree($userId, $depth = 2)
    {
        $user = User::find($userId);
        if (!$user) return null;

        return $this->buildNetworkTree($user, min($depth, $this->maxLevels));
    }

    protected function buildNetworkTree(User $user, $depth, $currentLevel = 1)
    {
        if ($currentLevel > $depth) {
            return null;
        }

        $referrals = User::where('sponsor_id', $user->id)
            ->select('id', 'name', 'email', 'member_code', 'is_active', 'rank_id', 'created_at')
            ->withCount(['commissions', 'orders'])
            ->get();

        $tree = [
            'user' => $user,
            'level' => $currentLevel,
            'children' => []
        ];

        foreach ($referrals as $referral) {
            $childTree = $this->buildNetworkTree($referral, $depth, $currentLevel + 1);
            if ($childTree) {
                $tree['children'][] = $childTree;
            }
        }

        return $tree;
    }

    public function getNetworkStats($userId)
    {
        $stats = ['total_network' => 0, 'levels' => []];

        for ($level = 1; $level <= $this->maxLevels; $level++) {
            $count = $this->getNetworkCountAtLevel($userId, $level);
            $stats['levels'][$level] = $count;
            $stats['total_network'] += $count;
        }

        $stats['total_commissions'] = Commission::where('user_id', $userId)
            ->where('status', 'paid')
            ->sum('amount');

        $stats['pending_commissions'] = Commission::where('user_id', $userId)
            ->where('status', 'pending')
            ->sum('amount');

        $stats['active_members'] = Referral::where('sponsor_id', $userId)
            ->whereHas('referred', function ($q) {
                $q->where('is_active', true);
            })
            ->count();

        $stats['inactive_members'] = Referral::where('sponsor_id', $userId)
            ->whereHas('referred', function ($q) {
                $q->where('is_active', false);
            })
            ->count();

        return $stats;
    }

    protected function getNetworkCountAtLevel($userId, $level)
    {
        return Referral::where('sponsor_id', $userId)
            ->where('level', $level)
            ->count();
    }

    public function getTeamSales($userId, $startDate = null, $endDate = null)
    {
        $query = Order::whereIn('user_id', function ($q) use ($userId) {
            $q->select('referred_id')
              ->from('referrals')
              ->where('sponsor_id', $userId);
        })->where('status', 'delivered');

        if ($startDate) {
            $query->where('created_at', '>=', $startDate);
        }
        if ($endDate) {
            $query->where('created_at', '<=', $endDate);
        }

        return $query->sum('total_amount');
    }

    public function checkRankProgression(User $user)
    {
        $currentRank = $user->rank;
        $nextRank = Rank::active()
            ->where('level', '>', $currentRank ? $currentRank->level : 0)
            ->orderBy('level')
            ->first();

        if (!$nextRank) {
            return null;
        }

        if ($nextRank->checkQualification($user)) {
            $user->update(['rank_id' => $nextRank->id]);

            Log::info('Rang utilisateur mis à jour', [
                'user_id' => $user->id,
                'old_rank' => $currentRank ? $currentRank->name : 'Aucun',
                'new_rank' => $nextRank->name
            ]);

            $this->giveRankBonus($user, $nextRank);

            return $nextRank;
        }

        return null;
    }

    protected function giveRankBonus(User $user, Rank $rank)
    {
        // Vérifier si l'utilisateur a déjà reçu ce bonus de rang
        $existingBonus = Commission::where('user_id', $user->id)
            ->where('type', 'rank_bonus')
            ->where('description', "Bonus de rang: {$rank->name}")
            ->exists();
        
        if ($existingBonus) {
            Log::info('Bonus de rang déjà attribué', ['user_id' => $user->id, 'rank' => $rank->name]);
            return;
        }

        // Utiliser bonus_amount du rang ou fallback sur Settings
        $bonusAmount = floatval($rank->bonus_amount ?? 0);
        if ($bonusAmount <= 0) {
            $bonusAmount = floatval(Setting::get("rank_bonus_{$rank->slug}", 0));
        }
        
        if ($bonusAmount > 0) {
            $commission = Commission::create([
                'user_id' => $user->id,
                'order_id' => null,
                'from_user_id' => $user->id,
                'type' => 'rank_bonus',
                'level' => 0,
                'amount' => $bonusAmount,
                'status' => 'approved',
                'description' => "Bonus de rang: {$rank->name}"
            ]);

            $this->creditWallet($user, $bonusAmount, $commission);

            Log::info('Bonus de rang attribué', [
                'user_id' => $user->id,
                'rank' => $rank->name,
                'amount' => $bonusAmount
            ]);
        }

        // Appliquer le bonus de commission en pourcentage si applicable
        if ($rank->commission_bonus > 0) {
            Log::info('Commission bonus pourcentage activé', [
                'user_id' => $user->id,
                'rank' => $rank->name,
                'percentage' => $rank->commission_bonus
            ]);
        }
    }

    public function getLeaderboard($period = 'month', $limit = 10)
    {
        $query = Commission::select('user_id', DB::raw('SUM(amount) as total_earned'))
            ->where('status', 'paid');

        switch ($period) {
            case 'week':
                $query->where('created_at', '>=', now()->startOfWeek());
                break;
            case 'month':
                $query->where('created_at', '>=', now()->startOfMonth());
                break;
            case 'year':
                $query->where('created_at', '>=', now()->startOfYear());
                break;
        }

        return $query->groupBy('user_id')
            ->orderByDesc('total_earned')
            ->limit($limit)
            ->with('user:id,name,email,member_code,rank_id')
            ->get();
    }

    public function initializeDefaultLevels()
    {
        $defaultLevels = [
            ['level' => 1, 'name' => 'Niveau 1 - Filleul Direct', 'commission_rate' => 10, 'bonus_rate' => 0, 'is_active' => true],
            ['level' => 2, 'name' => 'Niveau 2 - Filleul Indirect', 'commission_rate' => 5, 'bonus_rate' => 0, 'is_active' => true],
        ];

        foreach ($defaultLevels as $level) {
            MlmLevel::updateOrCreate(
                ['level' => $level['level']],
                $level
            );
        }

        MlmLevel::where('level', '>', 2)->update(['is_active' => false]);

        Log::info('Niveaux MLM initialisés (2 niveaux uniquement)', ['count' => count($defaultLevels)]);
    }

    public function initializeDefaultRanks()
    {
        $defaultRanks = [
            [
                'name' => 'Débutant',
                'slug' => 'debutant',
                'level' => 0,
                'min_personal_sales' => 0,
                'min_team_sales' => 0,
                'min_direct_referrals' => 0,
                'commission_bonus' => 0,
                'badge_color' => '#6B7280'
            ],
            [
                'name' => 'Bronze',
                'slug' => 'bronze',
                'level' => 1,
                'min_personal_sales' => 50000,
                'min_team_sales' => 100000,
                'min_direct_referrals' => 3,
                'commission_bonus' => 1,
                'badge_color' => '#CD7F32'
            ],
            [
                'name' => 'Argent',
                'slug' => 'argent',
                'level' => 2,
                'min_personal_sales' => 150000,
                'min_team_sales' => 500000,
                'min_direct_referrals' => 5,
                'commission_bonus' => 2,
                'badge_color' => '#C0C0C0'
            ],
            [
                'name' => 'Or',
                'slug' => 'or',
                'level' => 3,
                'min_personal_sales' => 300000,
                'min_team_sales' => 1500000,
                'min_direct_referrals' => 10,
                'commission_bonus' => 3,
                'badge_color' => '#FFD700'
            ],
            [
                'name' => 'Platine',
                'slug' => 'platine',
                'level' => 4,
                'min_personal_sales' => 500000,
                'min_team_sales' => 5000000,
                'min_direct_referrals' => 15,
                'commission_bonus' => 4,
                'badge_color' => '#E5E4E2'
            ],
            [
                'name' => 'Diamant',
                'slug' => 'diamant',
                'level' => 5,
                'min_personal_sales' => 1000000,
                'min_team_sales' => 15000000,
                'min_direct_referrals' => 25,
                'commission_bonus' => 5,
                'badge_color' => '#B9F2FF'
            ],
        ];

        foreach ($defaultRanks as $rank) {
            Rank::updateOrCreate(
                ['slug' => $rank['slug']],
                $rank
            );
        }

        Log::info('Rangs MLM initialisés', ['count' => count($defaultRanks)]);
    }
}
