"""
Modèle Outlook - GMAO Collège
Intégration avec Outlook/Microsoft
"""
from datetime import datetime, timezone
from app_new.extensions import db
from sqlalchemy.dialects.mysql import LONGTEXT, LONGBLOB


class OutlookAccount(db.Model):
    """Compte Outlook connecté."""
    __tablename__ = "outlook_accounts"
    
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey("users.id"), nullable=False)
    email = db.Column(db.String(255), nullable=False)
    tenant_id = db.Column(db.String(100), nullable=False)
    refresh_token = db.Column(db.Text, nullable=True)
    client_id = db.Column(db.String(100), nullable=True)
    is_active = db.Column(db.Boolean, default=True)
    last_connected_at = db.Column(db.DateTime, nullable=True)
    connection_status = db.Column(db.String(20), nullable=True)
    scopes = db.Column(db.Text, nullable=True)
    device_code = db.Column(db.Text, nullable=True)
    device_code_expires_at = db.Column(db.DateTime, nullable=True)
    user_code = db.Column(db.String(20), nullable=True)
    created_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc))
    updated_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc))
    
    # Relations
    user = db.relationship("User", backref="outlook_accounts")
    folders = db.relationship("OutlookFolder", backref="account", cascade="all, delete-orphan")
    
    def __repr__(self):
        return f"<OutlookAccount {self.email}>"


class OutlookFolder(db.Model):
    """Dossier Outlook (Boîte de réception, Éléments envoyés, etc.)."""
    __tablename__ = "outlook_folders"
    
    id = db.Column(db.String(500), primary_key=True)  # Folder ID from Microsoft
    account_id = db.Column(db.Integer, db.ForeignKey("outlook_accounts.id"), nullable=False)
    name = db.Column(db.String(255), nullable=False)
    display_name = db.Column(db.String(255), nullable=True)
    parent_id = db.Column(db.String(500), db.ForeignKey('outlook_folders.id'), nullable=True)  # Pour les sous-dossiers
    total_items = db.Column(db.Integer, default=0)
    unread_items = db.Column(db.Integer, default=0)
    folder_type = db.Column(db.String(50), nullable=True)  # inbox, sentitems, drafts, etc.
    created_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc))
    
    # Relations
    mails = db.relationship("OutlookMail", backref="folder", cascade="all, delete-orphan")
    children = db.relationship("OutlookFolder", backref="parent", remote_side=[id])
    
    def __repr__(self):
        return f"<OutlookFolder {self.display_name or self.name}>"


class OutlookMail(db.Model):
    """Email Outlook synchronisé."""
    __tablename__ = "outlook_mails"
    
    id = db.Column(db.String(500), primary_key=True)  # Message ID from Microsoft
    account_id = db.Column(db.Integer, db.ForeignKey("outlook_accounts.id"), nullable=False)
    folder_id = db.Column(db.String(500), db.ForeignKey("outlook_folders.id"), nullable=True)
    subject = db.Column(db.Text, nullable=True)
    sender = db.Column(db.String(255), nullable=True)
    sender_email = db.Column(db.String(255), nullable=True)
    body_preview = db.Column(db.Text, nullable=True)
    # Un corps HTML Outlook dépasse fréquemment la limite de 64 Kio de TEXT.
    body_content = db.Column(LONGTEXT, nullable=True)
    body_type = db.Column(db.String(20), nullable=True)  # html ou text
    received_at = db.Column(db.DateTime, nullable=True)
    is_read = db.Column(db.Boolean, default=False)
    importance = db.Column(db.String(20), nullable=True)
    has_attachments = db.Column(db.Boolean, default=False)
    attachment_count = db.Column(db.Integer, nullable=True)
    from_name = db.Column(db.String(255), nullable=True)
    from_email = db.Column(db.String(255), nullable=True)
    to_recipients = db.Column(db.Text, nullable=True)  # JSON
    cc_recipients = db.Column(db.Text, nullable=True)  # JSON
    bcc_recipients = db.Column(db.Text, nullable=True)  # JSON
    created_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc))
    
    # Relations
    account = db.relationship("OutlookAccount", backref="mails")
    attachments = db.relationship("OutlookAttachment", backref="mail", cascade="all, delete-orphan")
    interpretations = db.relationship("OutlookMailInterpretation", backref="mail", cascade="all, delete-orphan")
    
    def __repr__(self):
        return f"<OutlookMail {self.subject}>"


class OutlookAttachment(db.Model):
    """Pièce jointe d'un email Outlook."""
    __tablename__ = "outlook_attachments"
    
    # Les identifiants Microsoft Graph peuvent dépasser 100 caractères.
    id = db.Column(db.String(500), primary_key=True)  # Attachment ID from Microsoft
    mail_id = db.Column(db.String(500), db.ForeignKey("outlook_mails.id"), nullable=False)
    name = db.Column(db.String(500), nullable=False)
    content_type = db.Column(db.String(100), nullable=True)
    size = db.Column(db.Integer, default=0)
    is_inline = db.Column(db.Boolean, default=False)
    content_id = db.Column(db.String(200), nullable=True)  # Pour les images inline
    # Les PDF et documents doivent pouvoir dépasser 64 Kio (BLOB).
    content = db.Column(LONGBLOB, nullable=True)  # Contenu binaire de la pièce jointe
    
    def __repr__(self):
        return f"<OutlookAttachment {self.name}>"


class OutlookMailInterpretation(db.Model):
    """Interprétation Hermes d'un email avec analyse structurée."""
    __tablename__ = "outlook_mail_interpretations"
    
    id = db.Column(db.Integer, primary_key=True)
    mail_id = db.Column(db.String(500), db.ForeignKey("outlook_mails.id"), nullable=False)
    user_id = db.Column(db.Integer, db.ForeignKey("users.id"), nullable=False)
    
    # Analyse brute (texte de l'IA)
    interpretation = db.Column(db.Text, nullable=False)
    
    # Analyse structurée (JSON parsé)
    analysis_type = db.Column(db.String(20), nullable=True)  # curative, preventive, information
    analysis_action = db.Column(db.String(20), nullable=True)  # create, update, inform
    
    # Données de l'intervention suggérée
    suggested_title = db.Column(db.String(255), nullable=True)
    suggested_description = db.Column(db.Text, nullable=True)
    suggested_urgency = db.Column(db.String(20), nullable=True)  # basse, normale, haute, urgente
    suggested_location = db.Column(db.String(255), nullable=True)
    suggested_equipment = db.Column(db.String(255), nullable=True)
    suggested_assignee = db.Column(db.String(255), nullable=True)
    suggested_date = db.Column(db.DateTime, nullable=True)  # Pour les préventives
    
    # Lien vers intervention existante (si mise à jour)
    existing_intervention_id = db.Column(db.Integer, db.ForeignKey("interventions.id"), nullable=True)
    
    # Contexte utilisateur
    user_context = db.Column(db.Text, nullable=True)
    
    # Métadonnées
    raw_json = db.Column(db.Text, nullable=True)  # JSON complet stocké
    confidence_score = db.Column(db.Float, nullable=True)  # Score de confiance de l'analyse
    status = db.Column(db.String(20), default='pending')  # pending, accepted, rejected
    created_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc))
    
    # Relations
    user = db.relationship("User", backref="outlook_interpretations")
    
    def get_parsed_analysis(self):
        """Retourne l'analyse parsée depuis le JSON stocké."""
        if self.raw_json:
            import json
            try:
                return json.loads(self.raw_json)
            except:
                pass
        return None
    
    def set_from_parsed(self, parsed_data):
        """Définit les champs depuis le JSON parsé."""
        self.analysis_type = parsed_data.get('type')
        self.analysis_action = parsed_data.get('action')
        
        intervention = parsed_data.get('intervention', {})
        self.suggested_title = intervention.get('titre')
        self.suggested_description = intervention.get('description')
        self.suggested_urgency = intervention.get('urgence')
        self.suggested_location = intervention.get('lieu')
        self.suggested_equipment = intervention.get('equipement')
        self.suggested_assignee = intervention.get('intervenant_suggere')
        
        # Extraire la date (peut être dans intervention.date_intervention ou date_suggestion)
        date_str = intervention.get('date_intervention') or parsed_data.get('date_suggestion')
        if date_str:
            try:
                from datetime import datetime, timezone
                self.suggested_date = datetime.strptime(date_str, '%Y-%m-%d')
            except:
                pass
        
        if parsed_data.get('intervention_existante_id'):
            self.existing_intervention_id = parsed_data['intervention_existante_id']
        
        import json
        self.raw_json = json.dumps(parsed_data, ensure_ascii=False)
    
    def __repr__(self):
        return f"<OutlookMailInterpretation mail={self.mail_id} type={self.analysis_type}>"


class GmaoContext(db.Model):
    """Contexte GMAO pour l'interprétation des emails par Hermes.
    
    Stocke les informations contextuelles sur l'établissement,
    les équipements, les procédures, etc. pour aider Hermes
    à mieux interpréter les demandes.
    """
    __tablename__ = "gmao_context"
    __table_args__ = {'extend_existing': True}
    
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey("users.id"), nullable=False, unique=True)
    
    # Informations sur l'établissement
    establishment_name = db.Column(db.String(200), nullable=True)  # ex: "Collège Jean Jaurès"
    establishment_type = db.Column(db.String(100), nullable=True)  # ex: "Collège public"
    address = db.Column(db.Text, nullable=True)
    
    # Contexte technique
    technical_context = db.Column(db.Text, nullable=True)  # Info sur les bâtiments, surfaces, etc.
    equipment_context = db.Column(db.Text, nullable=True)  # Liste des équipements principaux
    procedure_context = db.Column(db.Text, nullable=True)  # Procédures spécifiques
    
    # Contexte organisationnel
    staff_info = db.Column(db.Text, nullable=True)  # Info sur le personnel
    contact_info = db.Column(db.Text, nullable=True)  # Contacts utiles (entreprises, etc.)
    
    # Instructions personnalisées pour Hermes
    hermes_instructions = db.Column(db.Text, nullable=True)  # Instructions spécifiques pour l'IA
    
    # Expéditeurs à exclure de l'interprétation (newsletter, spam, etc.)
    excluded_senders = db.Column(db.Text, nullable=True)  # Un email par ligne
    
    # Configuration de l'interprétation automatique
    auto_interpret_enabled = db.Column(db.Boolean, default=False)
    auto_interpret_interval = db.Column(db.Integer, default=10)  # Minutes entre chaque vérification
    auto_interpret_folder = db.Column(db.String(100), default='inbox')  # Dossier à surveiller
    auto_interpret_max_emails = db.Column(db.Integer, default=10)  # Max emails par exécution
    auto_interpret_lookback_hours = db.Column(db.Integer, default=24)  # Heures en arrière pour chercher les emails
    
    # Configuration synchronisation PRONOTE
    pronote_sync_enabled = db.Column(db.Boolean, default=False)
    pronote_sync_interval = db.Column(db.Integer, default=360)  # Minutes entre chaque sync (6h par défaut)
    pronote_sync_weeks = db.Column(db.Integer, default=4)  # Nombre de semaines à synchroniser
    
    # Configuration synchronisation Outlook
    outlook_sync_enabled = db.Column(db.Boolean, default=True)
    outlook_sync_interval = db.Column(db.Integer, default=10)  # Minutes entre chaque vérification
    outlook_sync_lookback_hours = db.Column(db.Integer, default=24)  # Heures en arrière pour chercher les emails
    
    # Configuration IA
    # Provider IA : 'openrouter' (cloud) ou 'ollama' (local avec auto-identification)
    ai_provider = db.Column(db.String(20), default='openrouter')  # openrouter|ollama
    # Modèle Ollama local (ex: gemma3:4b-it, qwen2.5:3b)
    ollama_model = db.Column(db.String(100), nullable=True)
    
    # Watchdog interne (cron local)
    watchdog_enabled = db.Column(db.Boolean, default=False)
    watchdog_interval = db.Column(db.Integer, default=10)  # Minutes
    
    # Métadonnées
    created_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc))
    updated_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc))
    
    # Relations
    user = db.relationship("User", backref="gmao_context", uselist=False)
    
    @staticmethod
    def get_for_user(user_id):
        """Récupère ou crée le contexte GMAO pour un utilisateur."""
        context = GmaoContext.query.filter_by(user_id=user_id).first()
        if not context:
            context = GmaoContext(user_id=user_id)
            db.session.add(context)
            db.session.commit()
        return context
    
    def get_full_context(self):
        """Retourne le contexte complet formaté pour Hermes."""
        parts = []
        
        if self.establishment_name:
            parts.append(f"Établissement: {self.establishment_name}")
            if self.establishment_type:
                parts[-1] += f" ({self.establishment_type})"
        
        if self.address:
            parts.append(f"Adresse: {self.address}")
        
        if self.technical_context:
            parts.append(f"Contexte technique:\n{self.technical_context}")
        
        if self.equipment_context:
            parts.append(f"Équipements:\n{self.equipment_context}")
        
        if self.procedure_context:
            parts.append(f"Procédures:\n{self.procedure_context}")
        
        if self.staff_info:
            parts.append(f"Personnel:\n{self.staff_info}")
        
        if self.contact_info:
            parts.append(f"Contacts:\n{self.contact_info}")
        
        if self.hermes_instructions:
            parts.append(f"Instructions:\n{self.hermes_instructions}")
        
        return "\n\n".join(parts) if parts else ""
    
    def is_sender_excluded(self, sender_email):
        """Vérifie si un expéditeur est dans la liste d'exclusion."""
        if not self.excluded_senders or not sender_email:
            return False
        excluded = [e.strip().lower() for e in self.excluded_senders.split('\n') if e.strip()]
        return sender_email.lower() in excluded
    
    def get_excluded_senders_list(self):
        """Retourne la liste des expéditeurs exclus."""
        if not self.excluded_senders:
            return []
        return [e.strip() for e in self.excluded_senders.split('\n') if e.strip()]
    
    def __repr__(self):
        return f"<GmaoContext user={self.user_id}>"



# Note: Les routes Outlook sont dans app_new/outlook/routes.py
# Les templates sont dans app_new/outlook/templates/
