import unittest
from unittest.mock import AsyncMock, MagicMock, patch
import os
import json
import asyncio

# On injecte les vrais IDs à 18 chiffres de ton .env pour le test
os.environ["STARTER_SKU_ID"] = "111111111111111111"
os.environ["MEDIUM_SKU_ID"] = "222222222222222222"
os.environ["LARGE_SKU_ID"] = "333333333333333333"

from utils.premium import load_partners_whitelist, get_sku_ids, check_premium_tier, WHITELIST_PARTNERS_FILE

class TestPremiumSystem(unittest.IsolatedAsyncioTestCase):
    
    def setUp(self):
        # Nettoyage du fichier JSON avant chaque test
        if os.path.exists(WHITELIST_PARTNERS_FILE):
            try:
                os.remove(WHITELIST_PARTNERS_FILE)
            except Exception:
                pass

    def tearDown(self):
        # Nettoyage du fichier JSON après chaque test
        if os.path.exists(WHITELIST_PARTNERS_FILE):
            try:
                os.remove(WHITELIST_PARTNERS_FILE)
            except Exception:
                pass

    async def test_get_sku_ids(self):
        """Vérifie que la lecture du .env convertit bien les chaînes en nombres entiers (int)"""
        starter, medium, large = get_sku_ids()
        self.assertEqual(starter, 111111111111111111)
        self.assertEqual(medium, 222222222222222222)
        self.assertEqual(large, 333333333333333333)

    async def test_load_partners_whitelist_empty(self):
        """Vérifie que le système gère proprement un fichier whitelist vide sans crasher"""
        partners = await load_partners_whitelist()
        self.assertEqual(partners, [])
        self.assertTrue(os.path.exists(WHITELIST_PARTNERS_FILE))

    async def test_load_partners_whitelist_with_data(self):
        """Vérifie le chargement des partenaires depuis le fichier JSON"""
        with open(WHITELIST_PARTNERS_FILE, "w") as f:
            json.dump({"partners": [123, 456]}, f)
        partners = await load_partners_whitelist()
        self.assertEqual(partners, [123, 456])

    async def test_check_premium_tier_dm_fails(self):
        """Vérifie que le bot bloque proprement les commandes exécutées en DM (hors serveur)"""
        interaction = MagicMock()
        interaction.guild = None
        interaction.response = MagicMock()
        interaction.response.send_message = AsyncMock()
        
        decorator = check_premium_tier()
        predicate = decorator.predicate
        
        result = await predicate(interaction)
        self.assertFalse(result)
        interaction.response.send_message.assert_called_once_with(
            "❌ Cette commande ne peut être exécutée que sur un serveur Discord.",
            ephemeral=True
        )

    async def test_check_premium_tier_whitelist_passes(self):
        """Vérifie qu'un serveur dans la Whitelist passe sans condition, même sans SKU"""
        with open(WHITELIST_PARTNERS_FILE, "w") as f:
            json.dump({"partners": [12345]}, f)
            
        interaction = MagicMock()
        interaction.guild = MagicMock()
        interaction.guild.id = 12345
        interaction.response = MagicMock()
        interaction.response.send_message = AsyncMock()
        
        decorator = check_premium_tier()
        predicate = decorator.predicate
        
        result = await predicate(interaction)
        self.assertTrue(result)
        interaction.response.send_message.assert_not_called()

    async def test_check_premium_tier_invalid_member_count_fails(self):
        """Vérifie la sécurité (Fail-Safe) si le nombre de membres Discord renvoie une erreur"""
        interaction = MagicMock()
        interaction.guild = MagicMock()
        interaction.guild.id = 999
        interaction.guild.member_count = None
        interaction.response = MagicMock()
        interaction.response.send_message = AsyncMock()
        
        decorator = check_premium_tier()
        predicate = decorator.predicate
        
        result = await predicate(interaction)
        self.assertFalse(result)
        interaction.response.send_message.assert_called_once_with(
            "❌ Impossible de vérifier la taille du serveur par sécurité. Veuillez réessayer plus tard.",
            ephemeral=True
        )

    async def test_check_premium_tier_less_than_500_with_starter(self):
        """Vérifie qu'un petit serveur (<500 membres) avec le SKU Starter est bien AUTORISÉ"""
        interaction = MagicMock()
        interaction.guild = MagicMock()
        interaction.guild.id = 999
        interaction.guild.member_count = 100
        interaction.response = MagicMock()
        interaction.response.send_message = AsyncMock()
        
        entitlement = MagicMock()
        entitlement.sku_id = 111111111111111111
        entitlement.is_active.return_value = True
        interaction.entitlements = [entitlement]
        
        decorator = check_premium_tier()
        predicate = decorator.predicate
        
        result = await predicate(interaction)
        self.assertTrue(result)

    async def test_check_premium_tier_500_to_2500_with_starter_only_fails(self):
        """Vérifie qu'un serveur moyen qui a grandi (>500 membres) est BLOQUÉ s'il n'a qu'un SKU Starter"""
        interaction = MagicMock()
        interaction.guild = MagicMock()
        interaction.guild.id = 999
        interaction.guild.member_count = 1000
        interaction.response = MagicMock()
        interaction.response.send_message = AsyncMock()
        
        entitlement = MagicMock()
        entitlement.sku_id = 111111111111111111
        entitlement.is_active.return_value = True
        interaction.entitlements = [entitlement]
        
        decorator = check_premium_tier()
        predicate = decorator.predicate
        
        result = await predicate(interaction)
        self.assertFalse(result)
        interaction.response.send_message.assert_called_once()
        self.assertIn("Palier Medium", interaction.response.send_message.call_args[0][0])

    async def test_check_premium_tier_500_to_2500_with_medium_passes(self):
        """Vérifie qu'un serveur moyen (1000 membres) avec le SKU Medium est bien AUTORISÉ"""
        interaction = MagicMock()
        interaction.guild = MagicMock()
        interaction.guild.id = 999
        interaction.guild.member_count = 1000
        interaction.response = MagicMock()
        interaction.response.send_message = AsyncMock()
        
        entitlement = MagicMock()
        entitlement.sku_id = 222222222222222222
        entitlement.is_active.return_value = True
        interaction.entitlements = [entitlement]
        
        decorator = check_premium_tier()
        predicate = decorator.predicate
        
        result = await predicate(interaction)
        self.assertTrue(result)

    async def test_check_premium_tier_above_2500_with_large_passes(self):
        """Vérifie qu'un très gros serveur (>2500 membres) avec le SKU Large est bien AUTORISÉ"""
        interaction = MagicMock()
        interaction.guild = MagicMock()
        interaction.guild.id = 999
        interaction.guild.member_count = 3000
        interaction.response = MagicMock()
        interaction.response.send_message = AsyncMock()
        
        entitlement = MagicMock()
        entitlement.sku_id = 333333333333333333
        entitlement.is_active.return_value = True
        interaction.entitlements = [entitlement]
        
        decorator = check_premium_tier()
        predicate = decorator.predicate
        
        result = await predicate(interaction)
        self.assertTrue(result)

    async def test_check_premium_tier_above_2500_with_medium_fails(self):
        """Vérifie qu'un très gros serveur (>2500 membres) est BLOQUÉ s'il n'a qu'un SKU Medium"""
        interaction = MagicMock()
        interaction.guild = MagicMock()
        interaction.guild.id = 999
        interaction.guild.member_count = 3000
        interaction.response = MagicMock()
        interaction.response.send_message = AsyncMock()
        
        entitlement = MagicMock()
        entitlement.sku_id = 222222222222222222
        entitlement.is_active.return_value = True
        interaction.entitlements = [entitlement]
        
        decorator = check_premium_tier()
        predicate = decorator.predicate
        
        result = await predicate(interaction)
        self.assertFalse(result)
        self.assertIn("Palier Large", interaction.response.send_message.call_args[0][0])

if __name__ == "__main__":
    unittest.main()
