"""Interprétation automatique des emails par Hermes."""

import os
import sys
import json
import requests
from datetime import datetime, timezone, timedelta

# Ajouter le chemin pour les imports
sys.path.insert(0, '/root/hermes-workspace/gmao-college')

from app_new import create_app, db
from app_new.outlook.models import OutlookAccount, OutlookMail, OutlookMailInterpretation, OutlookFolder, GmaoContext
from app_new.core.models import User


def get_openrouter_api_key():
    """Récupère la clé API OpenRouter depuis les paramètres."""
    from app_new.core.models.settings import AppSettings
    # AppSettings.get déchiffre les valeurs sensibles ``enc:...``.
    return AppSettings.get('openrouter_api_key')


def get_openrouter_model():
    """Recupere le nom du modele OpenRouter depuis les parametres."""
    from app_new.core.models.settings import AppSettings
    return AppSettings.get('openrouter_model', 'poolside/laguna-m.1:free')


def get_ollama_model(gmao_context=None):
    """Récupère le nom du modèle Ollama depuis le contexte ou AppSettings."""
    from app_new.core.models.settings import AppSettings
    if gmao_context and gmao_context.ollama_model:
        return gmao_context.ollama_model
    return AppSettings.get('ollama_model', 'gemma3:4b-it')

def analyze_email_with_hermes(mail, gmao_context):
    """Analyse un email avec Hermes et retourne les interprétations.
    
    Utilise OpenRouter (cloud) ou Ollama (local) selon la configuration ai_provider.
    """
    provider = gmao_context.ai_provider if gmao_context and gmao_context.ai_provider else 'openrouter'
    
    # Préparer le contenu de l'email
    email_content = f"""Sujet: {mail.subject or '(sans sujet)'}
De: {mail.from_name or 'Inconnu'}<{mail.from_email or ''}>
À: {mail.to_recipients or ''}
Date: {mail.received_at.strftime('%d/%m/%Y %H:%M') if mail.received_at else '-'}

Contenu:
{mail.body_content or mail.body_preview or '(pas de contenu)'}
"""

    # Ajouter les pièces jointes PDF
    if mail.attachments:
        from app_new.outlook.models import OutlookAttachment
        attachments = OutlookAttachment.query.filter_by(mail_id=mail.id).all()
        if attachments:
            email_content += "\n=== PIÈCES JOINTES ===\n"
            for att in attachments:
                email_content += f"- {att.name} ({att.content_type})\n"
                if att.name and att.name.lower().endswith('.pdf'):
                    # Extraction PDF
                    try:
                        import pdfplumber
                        import tempfile
                        if att.content:
                            with tempfile.NamedTemporaryFile(suffix='.pdf', delete=False) as f:
                                f.write(att.content)
                                f.flush()
                                with pdfplumber.open(f.name) as pdf:
                                    text = ""
                                    for i, page in enumerate(pdf.pages[:5]):
                                        text += page.extract_text() or ""
                                        if len(text) > 2000:
                                            break
                                    email_content += f"[CONTENU PDF]:\n{text[:2000]}\n"
                            os.unlink(f.name)
                    except Exception as e:
                        email_content += f"[Erreur extraction PDF: {e}]\n"

    # Construire le prompt
    prompt = """Tu es un assistant pour la GMAO (Gestion de Maintenance Assistée par Ordinaire) d'un établissement scolaire.

Analyse cet email et EXTRAIS les informations pour créer une ou plusieurs interventions/tâches.

IMPORTANT: Tu DOIS répondre UNIQUEMENT avec un JSON valide, sans texte avant ni après.

Types possibles:
- "curative": Panne, problème, réparation nécessaire (ex: fuite, équipement cassé)
- "preventive": Maintenance planifiée, contrôle périodique (ex: inspection, entretien)
- "administrative": Tâche administrative à effectuer (ex: déposer des documents, remplir un formulaire, rappel)
- "formation": Formation à suivre, session de formation (ex: formation sécurité, recyclage)
- "information": Information simple, pas d'action requise

Actions possibles:
- "create": Créer une nouvelle intervention/tâche
- "update": Mettre à jour une intervention existante
- "inform": Juste informer, pas d'action

Format de réponse OBLIGATOIRE:
{
  "analyses": [
    {
      "type": "curative|preventive|administrative|formation|information",
      "action": "create|update|inform",
      "title": "Titre court et précis de l'intervention",
      "description": "Description détaillée du problème ou de la tâche",
      "urgency": "haute|normale|basse",
      "location": "Lieu concerné (salle, bâtiment)",
      "equipment": "Équipement concerné (nom exact si identifiable, sinon 'Divers')",
      "suggested_date": "YYYY-MM-DD ou null",
      "notes": "Notes additionnelles"
    }
  ]
}

Si plusieurs tâches distinctes sont mentionnées, crée plusieurs entrées dans "analyses".
Si c'est juste de l'information sans action, utilise "action": "inform".
"""

    # Ajouter le contexte GMAO
    if gmao_context:
        full_context = gmao_context.get_full_context()
        if full_context:
            prompt += f"\n\n=== CONTEXTE GMAO ===\n{full_context}\n"

    prompt += f"\n\n=== EMAIL À ANALYSER ===\n{email_content}\n=== FIN DE L'EMAIL ===\n\nFournis ton analyse:"
    
    # Appeler le provider IA selon le choix
    try:
        if provider == 'ollama':
            return _call_ollama(prompt, gmao_context)
        else:
            return _call_openrouter(prompt, gmao_context)
    except Exception as e:
        return {'error': str(e)}


def _call_ollama(prompt, gmao_context):
    """Appelle le service Ollama local avec auto-identification."""
    model = get_ollama_model(gmao_context)
    ollama_host = os.environ.get('OLLAMA_HOST', 'http://ollama:11434')
    
    try:
        # Appel Ollama avec le modèle local
        response = requests.post(
            f'{ollama_host}/api/chat',
            json={
                'model': model,
                'messages': [{'role': 'user', 'content': prompt}],
                'stream': False,
                'options': {
                    'temperature': 0.1,
                    'num_ctx': 8192
                }
            },
            timeout=60
        )
        
        if response.status_code != 200:
            return {'error': f'Erreur Ollama: {response.status_code} - {response.text[:200]}'}
        
        data = response.json()
        content = data.get('message', {}).get('content', '')
    except requests.exceptions.ConnectionError:
        return {'error': 'Service Ollama inaccessible. Vérifiez que le container ollama tourne.'}
    except Exception as e:
        return {'error': f'Erreur Ollama: {str(e)}'}
    
    return _parse_json_response(content)


def _call_openrouter(prompt, gmao_context):
    """Appelle l'API OpenRouter (cloud)."""
    api_key = get_openrouter_api_key()
    if not api_key:
        return {'error': 'Clé API OpenRouter non configurée'}
    
    try:
        response = requests.post(
            'https://openrouter.ai/api/v1/chat/completions',
            headers={
                'Authorization': f'Bearer {api_key}',
                'Content-Type': 'application/json'
            },
            json={
                'model': get_openrouter_model(),
                'messages': [{'role': 'user', 'content': prompt}],
                'max_tokens': 2000
            },
            timeout=60
        )
        
        if response.status_code != 200:
            return {'error': f'Erreur API: {response.status_code}'}
        
        data = response.json()
        content = data.get('choices', [{}])[0].get('message', {}).get('content', '')
    except Exception as e:
        return {'error': str(e)}
    
    return _parse_json_response(content)


def _parse_json_response(content):
    """Parse la réponse JSON de l'IA et gère les erreurs de formattage."""
    try:
        # Nettoyer le contenu (enlever les balises markdown)
        if '```json' in content:
            content = content.split('```json')[1].split('```')[0]
        elif '```' in content:
            content = content.split('```')[1].split('```')[0]
        
        # Enlever les espaces et retours à la ligne
        content = content.strip()
        
        # Vérifier si le contenu est vide
        if not content:
            return {'error': 'Réponse vide de l\'API', 'raw': ''}
        
        # Chercher le début du JSON ( { ou [ )
        json_start = content.find('{')
        if json_start == -1:
            json_start = content.find('[')
        if json_start > 0:
            content = content[json_start:]
        
        result = json.loads(content)
        return result
    except json.JSONDecodeError as e:
        # Logger l'erreur avec le contenu problématique
        print(f"[auto_interpret] Erreur JSON: {e}")
        print(f"[auto_interpret] Contenu reçu (500 premiers chars): {content[:500]}")
        return {'error': f'Impossible de parser la réponse: {str(e)}', 'raw': content[:500]}


def run_auto_interpret(user_id=None):
    """Exécute l'interprétation automatique pour les utilisateurs activés.
    
    Args:
        user_id: Si fourni, exécute uniquement pour cet utilisateur (mode manuel)
    
    Returns:
        dict: Résultat de l'exécution
    """
    # Si appelé depuis une route Flask, utiliser le contexte existant
    try:
        from flask import has_request_context
        if has_request_context():
            # Utiliser le contexte Flask existant
            return _run_auto_interpret_internal(user_id)
    except:
        pass
    
    # Sinon, créer une nouvelle application (mode cron)
    app = create_app()
    with app.app_context():
        return _run_auto_interpret_internal(user_id)


def _run_auto_interpret_internal(user_id=None):
    """Implémentation interne de l'interprétation automatique."""
    # Trouver les utilisateurs avec un contexte GMAO
    if user_id:
        contexts = GmaoContext.query.filter_by(user_id=user_id).all()
    else:
        contexts = GmaoContext.query.filter_by(auto_interpret_enabled=True).all()
    
    if not contexts:
        # Si pas de contexte, créer un contexte par défaut pour l'utilisateur
        if user_id:
            gmao_context = GmaoContext(user_id=user_id)
            db.session.add(gmao_context)
            db.session.commit()
            contexts = [gmao_context]
        else:
            return {'success': False, 'error': 'Aucun compte Outlook configuré. Veuillez d\'abord connecter votre compte Outlook.'}
    
    total_processed = 0
    total_created = 0
    errors = []
    
    for gmao_context in contexts:
        user = User.query.get(gmao_context.user_id)
        if not user:
            continue
        
        # Récupérer le compte Outlook
        account = OutlookAccount.query.filter_by(user_id=user.id, is_active=True).first()
        if not account:
            errors.append(f"Aucun compte Outlook actif pour l'utilisateur {user.id}")
            continue
        
        # Trouver les emails non interprétés des dernières 24h
        # Uniquement les emails REÇUS (pas envoyés par l'utilisateur)
        lookback_hours = gmao_context.auto_interpret_lookback_hours or 24
        since = datetime.now(timezone.utc) - timedelta(hours=lookback_hours)
        
        # Récupérer le dossier "Boîte de réception" s'il existe
        inbox_folder = OutlookFolder.query.filter_by(
            account_id=account.id,
            name='Boîte de réception'
        ).first()
        
        if inbox_folder:
            # Filtrer par dossier Boîte de réception
            # On prend plus d'emails car certains seront exclus
            limit = (gmao_context.auto_interpret_max_emails or 10) * 3
            mails = OutlookMail.query.filter(
                OutlookMail.account_id == account.id,
                OutlookMail.folder_id == inbox_folder.id,
                OutlookMail.received_at >= since,
                ~OutlookMail.id.in_(
                    db.session.query(OutlookMailInterpretation.mail_id)
                )
            ).order_by(OutlookMail.received_at.desc()).limit(limit).all()
        else:
            # Si pas de dossier, filtrer par expéditeur (exclure les emails envoyés par l'utilisateur)
            limit = (gmao_context.auto_interpret_max_emails or 10) * 3
            mails = OutlookMail.query.filter(
                OutlookMail.account_id == account.id,
                OutlookMail.received_at >= since,
                OutlookMail.from_email != account.email,  # Exclure les emails envoyés
                ~OutlookMail.id.in_(
                    db.session.query(OutlookMailInterpretation.mail_id)
                )
            ).order_by(OutlookMail.received_at.desc()).limit(limit).all()
        
        processed_count = 0
        max_to_process = gmao_context.auto_interpret_max_emails or 10
        
        for mail in mails:
            # Arrêter si on a traité le nombre voulu
            if processed_count >= max_to_process:
                break
            
            processed_count += 1
            
            # Vérifier si l'expéditeur est exclu
            if mail.from_email and gmao_context.is_sender_excluded(mail.from_email):
                # Créer une interprétation refusée pour cet email
                interpretation = OutlookMailInterpretation(
                    mail_id=mail.id,
                    user_id=user.id,
                    interpretation=f"Email ignoré - expéditeur exclu: {mail.from_email}",
                    analysis_type='information',
                    analysis_action='ignore',
                    suggested_title=mail.subject or 'Email ignoré',
                    suggested_description=f"Email automatiquement ignoré car l'expéditeur '{mail.from_email}' est dans la liste d'exclusion.",
                    suggested_urgency='normale',
                    status='rejected'
                )
                db.session.add(interpretation)
                total_processed += 1
                continue
            
            # Analyser l'email
            result = analyze_email_with_hermes(mail, gmao_context)
            
            if 'error' in result:
                errors.append(f"Email {mail.id}: {result['error']}")
                continue
            
            # Créer les interprétations
            analyses = result.get('analyses', [])
            if not analyses:
                analyses = [result]  # Format legacy
            
            for analysis in analyses:
                # Créer toutes les interprétations, y compris les informations
                suggested_date = None
                if analysis.get('suggested_date'):
                    try:
                        suggested_date = datetime.strptime(analysis['suggested_date'], '%Y-%m-%d').date()
                    except:
                        pass
                
                interpretation = OutlookMailInterpretation(
                    mail_id=mail.id,
                    user_id=user.id,
                    interpretation=analysis.get('description', mail.subject or ''),
                    analysis_type=analysis.get('type', 'curative'),
                    analysis_action=analysis.get('action', 'create'),
                    suggested_title=analysis.get('title', mail.subject or 'Sans titre'),
                    suggested_description=analysis.get('description', ''),
                    suggested_urgency=analysis.get('urgency', 'normale'),
                    suggested_location=analysis.get('location', ''),
                    suggested_equipment=analysis.get('equipment', 'Divers'),
                    suggested_date=suggested_date,
                    user_context=gmao_context.get_full_context() if gmao_context else '',
                    status='pending'
                )
                db.session.add(interpretation)
                total_created += 1
            
            total_processed += 1
        
        db.session.commit()
    
    return {
        'success': True,
        'processed': total_processed,
        'created': total_created,
        'errors': errors
    }


def get_last_run_status():
    """Retourne le statut de la dernière exécution."""
    # TODO: Implémenter un suivi des exécutions
    return {
        'last_run': None,
        'next_run': None,
        'emails_processed': 0
    }


if __name__ == '__main__':
    """Point d'entrée pour le cron."""
    result = run_auto_interpret()
    print(json.dumps(result, indent=2, ensure_ascii=False))
