# Fichier: blueprints/tools.py
"""
Blueprint pour les outils annexes (DNS Checker, futurs outils...).
Accessible aux utilisateurs pouvant réaliser des diagnostics.
"""

from flask import Blueprint, render_template, request, flash, redirect, url_for, current_app, send_file
from flask_login import login_required, current_user
from datetime import datetime, timezone
import json
import re

from extensions import db, limiter
from decorators import role_required
from models import DnsReport
from services.dns_service import (
    check_all_dns_security, 
    calculate_total_score, 
    get_max_score_breakdown,
    sanitize_domain
)

tools = Blueprint('tools', __name__, url_prefix='/tools', template_folder='../templates')

# ========================================================================
# HELPER - CONTRÔLE D'ACCÈS DNS
# ========================================================================

def can_access_dns_report(report):
    """Vérifie si l'utilisateur courant peut accéder au rapport DNS."""
    from models import User
    
    # Propriétaire du rapport
    if report.user_id == current_user.id:
        return True
    # Admin voit tout
    if current_user.role == 'admin':
        return True
    # Manager : clients, membres d'équipe, et patron
    if current_user.role == 'manager':
        owner = User.query.get(report.user_id)
        if owner:
            my_owner_id = current_user.owner_id
            # Client du manager (ou de son équipe)
            if owner.manager_id == my_owner_id:
                return True
            # Je suis le patron → voir rapports de mes membres
            if not current_user.parent_id and owner.parent_id == current_user.id:
                return True
            # Je suis un membre → voir rapports du patron et des autres membres
            if current_user.parent_id:
                if owner.id == my_owner_id or owner.parent_id == my_owner_id:
                    return True
    # Distributeur
    if current_user.role == 'distributor':
        owner = User.query.get(report.user_id)
        if owner:
            owner_id = current_user.owner_id
            team_ids = [u.id for u in User.query.filter(
                (User.id == owner_id) | (User.parent_id == owner_id)
            ).all()]
            # Cas 1 : User direct du distributeur
            if owner.distributor_id in team_ids:
                return True
            # Cas 2 : Client d'un manager du distributeur
            if owner.manager_id:
                manager = User.query.get(owner.manager_id)
                if manager and manager.distributor_id in team_ids:
                    return True
            # Cas 3 : Membre d'équipe d'un manager du distributeur
            if owner.parent_id:
                parent = User.query.get(owner.parent_id)
                if parent and parent.distributor_id in team_ids:
                    return True
    return False

# ========================================================================
# DNS CHECKER - INDEX
# ========================================================================

@tools.route('/dns', methods=['GET'])
@login_required
@role_required(['admin', 'manager', 'user'])
def dns_index():
    """Page d'accueil du DNS Checker."""
    
    # Récupérer l'historique des analyses de l'utilisateur
    recent_reports = DnsReport.query.filter_by(user_id=current_user.id)\
        .order_by(DnsReport.created_at.desc())\
        .limit(5)\
        .all()
    
    return render_template('tools/dns_index.html', recent_reports=recent_reports)


# ========================================================================
# DNS CHECKER - ANALYSE
# ========================================================================

@tools.route('/dns/analyze', methods=['POST'])
@login_required
@role_required(['admin', 'manager', 'user'])
@limiter.limit("20 per hour")
def dns_analyze():
    """Analyse DNS d'un domaine."""
    
    client_name = request.form.get('client_name', '').strip()
    domain = request.form.get('domain', '').strip().lower()
    dkim_selector = request.form.get('dkim_selector', 'default').strip() or 'default'
    
    # Validations
    if not client_name:
        flash("❌ Veuillez entrer le nom du client.", 'danger')
        return redirect(url_for('tools.dns_index'))
    
    if len(client_name) > 150:
        flash("❌ Nom du client trop long (max 150 caractères).", 'danger')
        return redirect(url_for('tools.dns_index'))
    
    clean_domain = sanitize_domain(domain)
    if not clean_domain:
        flash("❌ Nom de domaine invalide. Exemple : example.com", 'danger')
        return redirect(url_for('tools.dns_index'))
    
    # Validation sélecteur DKIM
    if not re.match(r'^[a-zA-Z0-9_-]+$', dkim_selector):
        dkim_selector = 'default'
    
    # Lancer l'analyse
    try:
        results = check_all_dns_security(clean_domain, dkim_selector)
        
        # Erreur fatale ?
        if "FATAL_ERROR" in results:
            error = results["FATAL_ERROR"]["detail"]
            current_app.logger.error(f"DNS Check fatal error: {error}")
            flash(f"❌ Erreur : {error}", 'danger')
            return redirect(url_for('tools.dns_index'))
        
        # Calcul du score
        score_data = calculate_total_score(results)
        total_score = score_data['score']
        max_score = score_data['max_score']
        score_color = score_data['color']
        
        # Sauvegarder le rapport en DB
        dns_report = DnsReport(
            client_name=client_name,
            domain=clean_domain,
            score=total_score,
            results_json=json.dumps(results, ensure_ascii=False),
            dkim_selector=dkim_selector,
            user_id=current_user.id
        )
        
        db.session.add(dns_report)
        db.session.commit()
        
        current_app.logger.info(
            f"🔍 DNS Check: {current_user.email} a analysé {clean_domain} "
            f"pour '{client_name}' (score: {total_score})"
        )
        
        # Afficher le rapport
        return render_template(
            'tools/dns_report.html',
            report=dns_report,
            results=results,
            score=total_score,
            max_score=max_score,
            score_color=score_color,
            protocol_max_scores=get_max_score_breakdown(),
            is_historical=False
        )
        
    except Exception as e:
        current_app.logger.error(f"Erreur DNS Check: {e}", exc_info=True)
        flash("❌ Erreur lors de l'analyse DNS. Veuillez réessayer.", 'danger')
        return redirect(url_for('tools.dns_index'))


# ========================================================================
# DNS CHECKER - RE-CHECK DKIM
# ========================================================================

@tools.route('/dns/recheck-dkim', methods=['POST'])
@login_required
@role_required(['admin', 'manager', 'user'])
@limiter.limit("20 per hour")
def dns_recheck_dkim():
    """Re-vérifie DKIM avec un sélecteur personnalisé."""
    
    client_name = request.form.get('client_name', '').strip()
    domain = request.form.get('domain', '').strip().lower()
    new_selector = request.form.get('new_dkim_selector', '').strip()
    
    if not new_selector:
        flash("❌ Veuillez entrer un sélecteur DKIM.", 'warning')
        return redirect(url_for('tools.dns_index'))
    
    if not client_name:
        client_name = "Client"
    
    # Validation du sélecteur
    if not re.match(r'^[a-zA-Z0-9_-]+$', new_selector):
        flash("❌ Sélecteur DKIM invalide (lettres, chiffres, tirets uniquement).", 'danger')
        return redirect(url_for('tools.dns_index'))
    
    clean_domain = sanitize_domain(domain)
    if not clean_domain:
        flash("❌ Nom de domaine invalide.", 'danger')
        return redirect(url_for('tools.dns_index'))
    
    # Lancer l'analyse avec le nouveau sélecteur
    try:
        results = check_all_dns_security(clean_domain, new_selector)
        
        if "FATAL_ERROR" in results:
            error = results["FATAL_ERROR"]["detail"]
            flash(f"❌ Erreur : {error}", 'danger')
            return redirect(url_for('tools.dns_index'))
        
        score_data = calculate_total_score(results)
        
        # Sauvegarder le nouveau rapport
        dns_report = DnsReport(
            client_name=client_name,
            domain=clean_domain,
            score=score_data['score'],
            results_json=json.dumps(results, ensure_ascii=False),
            dkim_selector=new_selector,
            user_id=current_user.id
        )
        
        db.session.add(dns_report)
        db.session.commit()
        
        current_app.logger.info(
            f"🔍 DNS Re-check DKIM: {current_user.email} - {clean_domain} "
            f"avec sélecteur '{new_selector}'"
        )
        
        return render_template(
            'tools/dns_report.html',
            report=dns_report,
            results=results,
            score=score_data['score'],
            max_score=score_data['max_score'],
            score_color=score_data['color'],
            protocol_max_scores=get_max_score_breakdown(),
            is_historical=False
        )
        
    except Exception as e:
        current_app.logger.error(f"Erreur DNS Re-check: {e}", exc_info=True)
        flash("❌ Erreur lors de la re-vérification.", 'danger')
        return redirect(url_for('tools.dns_index'))


# ========================================================================
# DNS CHECKER - HISTORIQUE
# ========================================================================

@tools.route('/dns/history')
@login_required
@role_required(['admin', 'manager', 'user'])
def dns_history():
    """Historique complet des analyses DNS avec filtres et tri."""
    
    page = request.args.get('page', 1, type=int)
    search = request.args.get('search', '').strip()
    sort = request.args.get('sort', 'date').strip()
    per_page = 20
    
    query = DnsReport.query.filter_by(user_id=current_user.id)
    
    # Filtre recherche (client_name ou domain)
    if search:
        from utils import escape_like_pattern
        search_escaped = escape_like_pattern(search)
        query = query.filter(
            db.or_(
                DnsReport.client_name.ilike(f'%{search_escaped}%', escape='\\'),
                DnsReport.domain.ilike(f'%{search_escaped}%', escape='\\')
            )
        )
    
    # Tri
    if sort == 'date':
        query = query.order_by(DnsReport.created_at.desc())
    elif sort == 'date_asc':
        query = query.order_by(DnsReport.created_at.asc())
    elif sort == 'score_desc':
        query = query.order_by(DnsReport.score.desc(), DnsReport.created_at.desc())
    elif sort == 'score_asc':
        query = query.order_by(DnsReport.score.asc(), DnsReport.created_at.desc())
    elif sort == 'client':
        query = query.order_by(DnsReport.client_name.asc(), DnsReport.created_at.desc())
    elif sort == 'domain':
        query = query.order_by(DnsReport.domain.asc(), DnsReport.created_at.desc())
    else:
        query = query.order_by(DnsReport.created_at.desc())
    
    pagination = query.paginate(page=page, per_page=per_page, error_out=False)
    
    return render_template(
        'tools/dns_history.html',
        reports=pagination.items,
        pagination=pagination,
        current_search=search,
        current_sort=sort
    )


# ========================================================================
# DNS CHECKER - VOIR RAPPORT
# ========================================================================

@tools.route('/dns/report/<string:report_id>')
@login_required
@role_required(['admin', 'manager', 'user', 'distributor'])
def dns_view_report(report_id):
    """Voir un rapport DNS sauvegardé."""
    
    report = DnsReport.query.get_or_404(report_id)
    
    # Sécurité : propriétaire, admin, ou manager du propriétaire
    if not can_access_dns_report(report):
        flash("❌ Accès non autorisé.", 'danger')
        if current_user.role == 'distributor':
            return redirect(url_for('distributor.distributor_dashboard'))
        return redirect(url_for('tools.dns_index'))
    
    # Décoder les résultats JSON
    try:
        results = json.loads(report.results_json)
    except json.JSONDecodeError:
        results = {}
    
    score_data = calculate_total_score(results)
    
    return render_template(
        'tools/dns_report.html',
        report=report,
        results=results,
        score=report.score,
        max_score=score_data['max_score'],
        score_color=score_data['color'],
        protocol_max_scores=get_max_score_breakdown(),
        is_historical=True
    )


# ========================================================================
# DNS CHECKER - SUPPRIMER RAPPORT
# ========================================================================

@tools.route('/dns/report/<string:report_id>/delete', methods=['POST'])
@login_required
@role_required(['admin', 'manager', 'user', 'distributor'])
def dns_delete_report(report_id):
    """Supprimer un rapport DNS."""
    
    report = DnsReport.query.get_or_404(report_id)
    
    # Sécurité
    if not can_access_dns_report(report):
        flash("❌ Accès non autorisé.", 'danger')
        return redirect(url_for('tools.dns_index'))
    
    try:
        client = report.client_name
        domain = report.domain
        db.session.delete(report)
        db.session.commit()
        
        current_app.logger.info(
            f"🗑️ DNS Report supprimé: {current_user.email} - {client} ({domain})"
        )
        flash("✅ Rapport supprimé.", 'success')
        
    except Exception as e:
        db.session.rollback()
        current_app.logger.error(f"Erreur suppression rapport DNS: {e}")
        flash("❌ Erreur lors de la suppression.", 'danger')
    
    return redirect(url_for('tools.dns_history'))


# ========================================================================
# DNS CHECKER - TÉLÉCHARGER PDF
# ========================================================================

@tools.route('/dns/report/<string:report_id>/pdf')
@login_required
@role_required(['admin', 'manager', 'user', 'distributor'])
def dns_download_pdf(report_id):
    """Télécharger le rapport DNS en PDF."""
    
    report = DnsReport.query.get_or_404(report_id)
    
    # Sécurité
    if not can_access_dns_report(report):
        flash("❌ Accès non autorisé.", 'danger')
        return redirect(url_for('tools.dns_index'))
    
    try:
        # Décoder les résultats
        results = json.loads(report.results_json)
        
        # Générer le PDF
        from services.pdf_service import generer_pdf_dns_rapport
        pdf_buffer = generer_pdf_dns_rapport(report, results)
        
        # Nom du fichier
        safe_name = re.sub(r'[^a-zA-Z0-9_-]', '_', report.client_name)[:30]
        filename = f"DNS_Rapport_{safe_name}_{report.domain}.pdf"
        
        current_app.logger.info(
            f"📥 PDF DNS téléchargé: {current_user.email} - {report.client_name}"
        )
        
        return send_file(
            pdf_buffer,
            mimetype='application/pdf',
            as_attachment=True,
            download_name=filename
        )
        
    except Exception as e:
        current_app.logger.error(f"Erreur génération PDF DNS: {e}", exc_info=True)
        flash("❌ Erreur lors de la génération du PDF.", 'danger')
        return redirect(url_for('tools.dns_view_report', report_id=report_id))