"""
DOOBAT - Tests unitaires AIService
Copyright 2026 Vincent Gallet - Vincesoft
"""

import configparser
import sys
import os
import unittest
from unittest.mock import MagicMock, patch

sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from services.ai_service import AIService


def make_config(api_key: str = "") -> configparser.ConfigParser:
    config = configparser.ConfigParser()
    config["OPENAI"] = {
        "api_key": api_key,
        "model": "gpt-4o-mini",
        "max_tokens": "500",
        "temperature": "0.1",
        "timeout": "20",
    }
    return config


class TestAIServiceRegexFallback(unittest.TestCase):
    """Tests du fallback regex (sans OpenAI)."""

    def setUp(self):
        # Pas de clé API → toujours fallback regex
        self.ai = AIService(make_config(api_key=""))

    # ── Intentions ──────────────────────────────────────────────

    def test_tarif_simple(self):
        result = self.ai.analyze_message("envoie le tarif")
        self.assertEqual(result["intent"], "tarif")
        self.assertGreater(result["confidence"], 0.5)

    def test_tarif_catalogue(self):
        result = self.ai.analyze_message("donne moi le catalogue")
        self.assertEqual(result["intent"], "tarif")

    def test_tarif_prix(self):
        result = self.ai.analyze_message("liste des prix")
        self.assertEqual(result["intent"], "tarif")

    def test_stock_simple(self):
        result = self.ai.analyze_message("stock du produit ABC")
        self.assertEqual(result["intent"], "stock")

    def test_stock_dispo(self):
        result = self.ai.analyze_message("disponibilité REF001")
        self.assertEqual(result["intent"], "stock")

    def test_stock_all_products(self):
        result = self.ai.analyze_message("stock de tous les produits")
        self.assertEqual(result["intent"], "stock")

    def test_stock_category(self):
        result = self.ai.analyze_message("stock de la catégorie Peinture")
        self.assertEqual(result["intent"], "stock")
        self.assertEqual(result["article_name"], "categorie: Peinture")

    def test_stock_category_natural_language(self):
        result = self.ai.analyze_message("je veux le stock de l'électricité")
        self.assertEqual(result["intent"], "stock")
        self.assertEqual(result["article_name"], "categorie: électricité")

    def test_documents_factures(self):
        result = self.ai.analyze_message("factures du client DUPONT")
        self.assertEqual(result["intent"], "client_documents")

    def test_documents_commandes(self):
        result = self.ai.analyze_message("commandes de Martin SAS")
        self.assertEqual(result["intent"], "client_documents")

    def test_documents_devis(self):
        result = self.ai.analyze_message("je veux les devis")
        self.assertEqual(result["intent"], "client_documents")

    def test_supplier_documents(self):
        result = self.ai.analyze_message("factures fournisseur ACME")
        self.assertEqual(result["intent"], "supplier_documents")
        self.assertEqual(result["supplier_name"], "ACME")

    def test_all_supplier_documents(self):
        result = self.ai.analyze_message("factures fournisseurs")
        self.assertEqual(result["intent"], "supplier_documents")
        self.assertEqual(result["supplier_name"], "")

    def test_help_simple(self):
        result = self.ai.analyze_message("aide")
        self.assertEqual(result["intent"], "help")

    def test_help_command(self):
        result = self.ai.analyze_message("/help")
        self.assertEqual(result["intent"], "help")

    def test_unknown(self):
        result = self.ai.analyze_message("bonjour comment vas tu")
        self.assertEqual(result["intent"], "unknown")
        self.assertEqual(result["confidence"], 0.0)

    # ── Extraction entités ──────────────────────────────────────

    def test_extract_article_name(self):
        result = self.ai.analyze_message("stock du produit REF-001-XYZ")
        self.assertEqual(result["intent"], "stock")
        # article_name doit contenir REF-001-XYZ

    def test_empty_message(self):
        result = self.ai.analyze_message("")
        self.assertEqual(result["intent"], "unknown")
        self.assertEqual(result["confidence"], 0.0)

    def test_none_like_empty(self):
        result = self.ai.analyze_message("   ")
        self.assertEqual(result["intent"], "unknown")

    # ── Validation ──────────────────────────────────────────────

    def test_result_has_all_keys(self):
        result = self.ai.analyze_message("tarif")
        self.assertIn("intent", result)
        self.assertIn("client_name", result)
        self.assertIn("article_name", result)
        self.assertIn("confidence", result)

    def test_confidence_between_0_and_1(self):
        for msg in ["tarif", "stock ref", "factures client TOTO", "aide", "xyz"]:
            result = self.ai.analyze_message(msg)
            self.assertGreaterEqual(result["confidence"], 0.0)
            self.assertLessEqual(result["confidence"], 1.0)


class TestAIServiceValidation(unittest.TestCase):
    """Tests de la méthode _validate_and_normalize."""

    def test_valid_data(self):
        data = {
            "intent": "tarif",
            "client_name": "Dupont SA",
            "article_name": "REF001",
            "confidence": 0.95,
        }
        result = AIService._validate_and_normalize(data)
        self.assertEqual(result["intent"], "tarif")
        self.assertEqual(result["confidence"], 0.95)

    def test_invalid_intent_defaults_to_unknown(self):
        data = {"intent": "invalid_intent", "confidence": 0.9}
        result = AIService._validate_and_normalize(data)
        self.assertEqual(result["intent"], "unknown")

    def test_confidence_clamp_above_1(self):
        data = {"intent": "tarif", "confidence": 1.5}
        result = AIService._validate_and_normalize(data)
        self.assertEqual(result["confidence"], 1.0)

    def test_confidence_clamp_below_0(self):
        data = {"intent": "tarif", "confidence": -0.5}
        result = AIService._validate_and_normalize(data)
        self.assertEqual(result["confidence"], 0.0)

    def test_long_client_name_truncated(self):
        data = {
            "intent": "client_documents",
            "client_name": "A" * 200,
            "confidence": 0.9,
        }
        result = AIService._validate_and_normalize(data)
        self.assertLessEqual(len(result["client_name"]), 100)

    def test_missing_fields_default(self):
        data = {"intent": "help"}
        result = AIService._validate_and_normalize(data)
        self.assertEqual(result["client_name"], "")
        self.assertEqual(result["article_name"], "")
        self.assertEqual(result["confidence"], 0.0)


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