import json, os, subprocess, sys, re, secrets
from datetime import datetime, timedelta
from flask import Flask, render_template, render_template_string, request, session, redirect, url_for, flash
from werkzeug.security import generate_password_hash, check_password_hash

app = Flask(__name__)
# Sécurité : utiliser une variable d'environnement pour la clé secrète en production
app.secret_key = os.environ.get("SECRET_KEY", "secret-key-dev-only")
app.config['DEBUG'] = os.environ.get("FLASK_DEBUG", "False").lower() == "true"

# --- CONFIG pourla page bilan ---
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
BILAN_JSON = os.path.join(BASE_DIR, "bilan.json")
CALCUL_SCRIPT = os.path.join(BASE_DIR, "calcul_bilan.py")

# Email du super utilisateur (peut voir tous les bilans)
SUPER_USER_EMAIL = "phi.robin@gmail.com"

# Email du super utilisateur (peut voir tous les bilans)
SUPER_USER_EMAIL = "phi.robin@gmail.com"

# Charger les sourates depuis quran.json
with open("data/quran.json", "r", encoding="utf-8") as f:
    QURAN = json.load(f)

# Charger les utilisateurs depuis users.json
def load_users():
    try:
        with open("users.json", "r", encoding="utf-8") as f:
            return json.load(f)
    except FileNotFoundError:
        return {}

# Sauvegarder les utilisateurs dans users.json
def save_users(users):
    with open("users.json", "w", encoding="utf-8") as f:
        json.dump(users, f, ensure_ascii=False, indent=2)

# Valider le format de l'email
def is_valid_email(email):
    pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
    return re.match(pattern, email) is not None

# Charger les tokens de réinitialisation depuis reset_tokens.json
def load_reset_tokens():
    try:
        with open("reset_tokens.json", "r", encoding="utf-8") as f:
            return json.load(f)
    except FileNotFoundError:
        return {}

# Sauvegarder les tokens de réinitialisation
def save_reset_tokens(tokens):
    with open("reset_tokens.json", "w", encoding="utf-8") as f:
        json.dump(tokens, f, ensure_ascii=False, indent=2)

# Créer un token de réinitialisation
def create_reset_token(email):
    token = secrets.token_urlsafe(32)
    tokens = load_reset_tokens()
    # Token valide pour 1 heure
    expires_at = (datetime.now() + timedelta(hours=1)).isoformat()
    tokens[token] = {
        "email": email,
        "expires_at": expires_at,
        "created_at": datetime.now().isoformat()
    }
    save_reset_tokens(tokens)
    return token

# Vérifier et valider un token de réinitialisation
def validate_reset_token(token):
    tokens = load_reset_tokens()
    if token not in tokens:
        return None
    
    token_data = tokens[token]
    expires_at = datetime.fromisoformat(token_data["expires_at"])
    
    # Vérifier si le token a expiré
    if datetime.now() > expires_at:
        # Supprimer le token expiré
        del tokens[token]
        save_reset_tokens(tokens)
        return None
    
    return token_data["email"]

# Supprimer un token utilisé
def remove_reset_token(token):
    tokens = load_reset_tokens()
    if token in tokens:
        del tokens[token]
        save_reset_tokens(tokens)

# Charger le suivi des utilisateurs
def load_progress():
    try:
        with open("progress.json", "r", encoding="utf-8") as f:
            return json.load(f)
    except FileNotFoundError:
        return {}

def save_progress(progress):
    with open("progress.json", "w", encoding="utf-8") as f:
        json.dump(progress, f, ensure_ascii=False, indent=2)


def creer_bilan(progress_file="progress.json", bilan_file="bilan.json", total_items=545):
    """
    Crée un fichier bilan.json indiquant le % d'avancement de chaque utilisateur
    à partir d'un fichier progress.json.
    """
    if not os.path.exists(progress_file):
        print(f"Erreur : le fichier {progress_file} est introuvable.")
        return
    
    with open(progress_file, "r") as f:
        data = json.load(f)

    bilan = {}
    for user, sessions in data.items():
        all_items = set()
        for session_items in sessions.values():
            all_items.update(session_items)
        progress_percent = (len(all_items) / total_items) * 100
        bilan[user] = round(progress_percent, 2)

    with open(bilan_file, "w") as f:
        json.dump(bilan, f, indent=2)

    print(f"✅ Fichier '{bilan_file}' créé avec succès.")
    print("Contenu :", bilan)


@app.route("/bilan")
def afficher_bilan():
    """Exécute le calcul de bilan et affiche la page HTML depuis un template."""
    # Vérifier que l'utilisateur est connecté
    if "username" not in session:
        return redirect(url_for("login"))
    
    current_user = session["username"]
    
    # 1️⃣ Lancer le script de calcul
    subprocess.run([sys.executable, CALCUL_SCRIPT], check=True)

    # 2️⃣ Charger les données JSON
    with open(BILAN_JSON, "r", encoding="utf-8") as f:
        all_data = json.load(f)

    # 3️⃣ Filtrer les données selon l'utilisateur
    # Super utilisateur : voir tous les bilans
    # Utilisateur normal : voir uniquement son propre bilan
    if current_user == SUPER_USER_EMAIL:
        # Super utilisateur : afficher tous les bilans
        data = all_data
        is_super_user = True
    else:
        # Utilisateur normal : afficher uniquement son propre bilan
        if current_user in all_data:
            data = {current_user: all_data[current_user]}
        else:
            data = {current_user: 0.0}  # Pas encore de progression
        is_super_user = False

    # 4️⃣ Renvoyer la page template avec les données filtrées
    return render_template("bilan.html", data=data, is_super_user=is_super_user, current_user=current_user)
        
@app.route("/register", methods=["GET", "POST"])
def register():
    if request.method == "POST":
        email = request.form.get("email", "").strip().lower()
        password = request.form.get("password", "")
        confirm_password = request.form.get("confirm_password", "")
        
        users = load_users()
        
        # Validation
        if not email or not password:
            return render_template("register.html", error="L'email et le mot de passe sont requis")
        
        if not is_valid_email(email):
            return render_template("register.html", error="Format d'email invalide")
        
        if password != confirm_password:
            return render_template("register.html", error="Les mots de passe ne correspondent pas")
        
        if len(password) < 6:
            return render_template("register.html", error="Le mot de passe doit contenir au moins 6 caractères")
        
        # Vérifier si l'email existe déjà
        if email in users:
            return render_template("register.html", error="Cet email est déjà utilisé")
        
        # Créer le compte avec mot de passe haché
        users[email] = generate_password_hash(password)
        save_users(users)
        
        return render_template("register.html", success="Compte créé avec succès ! Vous pouvez maintenant vous connecter.")
    
    return render_template("register.html")

@app.route("/login", methods=["GET", "POST"])
def login():
    if request.method == "POST":
        email = request.form.get("email", "").strip().lower()
        password = request.form.get("password", "")
        users = load_users()
        
        if not email or not password:
            return render_template("login.html", error="L'email et le mot de passe sont requis")
        
        # Vérifier les identifiants
        if email in users:
            # Vérifier si c'est un ancien format (mot de passe en clair) ou nouveau (haché)
            stored_password = users[email]
            # Vérifier si c'est un hash (pbkdf2, scrypt, ou argon2)
            if stored_password.startswith(('pbkdf2:', 'scrypt:', 'argon2')):
                if check_password_hash(stored_password, password):
                    session["username"] = email
                    return redirect(url_for("index"))
            elif stored_password == password:  # Ancien format (rétrocompatibilité)
                # Migrer vers le format haché
                users[email] = generate_password_hash(password)
                save_users(users)
                session["username"] = email
                return redirect(url_for("index"))
        
        return render_template("login.html", error="Email ou mot de passe incorrect")
    
    return render_template("login.html")

@app.route("/forgot_password", methods=["GET", "POST"])
def forgot_password():
    if request.method == "POST":
        email = request.form.get("email", "").strip().lower()
        users = load_users()
        
        if not email:
            return render_template("forgot_password.html", error="L'email est requis")
        
        if not is_valid_email(email):
            return render_template("forgot_password.html", error="Format d'email invalide")
        
        # Vérifier si l'email existe (mais ne pas le révéler pour la sécurité)
        if email in users:
            # Créer un token de réinitialisation
            token = create_reset_token(email)
            reset_url = request.url_root.rstrip('/') + url_for('reset_password', token=token)
            
            # En production, vous devriez envoyer un email ici
            # Pour l'instant, on affiche l'URL dans le message (à des fins de test)
            return render_template("forgot_password.html", 
                                 success=True, 
                                 reset_url=reset_url,
                                 message="Si cet email existe dans notre système, un lien de réinitialisation a été créé.")
        else:
            # Ne pas révéler si l'email existe ou non (sécurité)
            return render_template("forgot_password.html", 
                                 success=True,
                                 message="Si cet email existe dans notre système, un lien de réinitialisation a été créé.")
    
    return render_template("forgot_password.html")

@app.route("/reset_password/<token>", methods=["GET", "POST"])
def reset_password(token):
    # Vérifier que le token est valide
    email = validate_reset_token(token)
    
    if not email:
        return render_template("reset_password.html", 
                             error="Ce lien de réinitialisation est invalide ou a expiré. Veuillez faire une nouvelle demande.",
                             invalid_token=True)
    
    if request.method == "POST":
        password = request.form.get("password", "")
        confirm_password = request.form.get("confirm_password", "")
        
        if not password or not confirm_password:
            return render_template("reset_password.html", error="Tous les champs sont requis", token=token)
        
        if password != confirm_password:
            return render_template("reset_password.html", error="Les mots de passe ne correspondent pas", token=token)
        
        if len(password) < 6:
            return render_template("reset_password.html", error="Le mot de passe doit contenir au moins 6 caractères", token=token)
        
        # Mettre à jour le mot de passe
        users = load_users()
        if email in users:
            users[email] = generate_password_hash(password)
            save_users(users)
            
            # Supprimer le token utilisé
            remove_reset_token(token)
            
            return render_template("reset_password.html", success="Votre mot de passe a été réinitialisé avec succès ! Vous pouvez maintenant vous connecter.", token=None)
        else:
            return render_template("reset_password.html", error="Une erreur est survenue", token=token)
    
    return render_template("reset_password.html", token=token)

@app.route("/logout")
def logout():
    session.pop("username", None)
    return redirect(url_for("login"))

# Index : liste des sourates (mode card)
@app.route("/")
def index():
    if "username" not in session:
        return redirect(url_for("login"))
    
    username = session["username"]
    
    # Calculer le pourcentage d'avancement de l'utilisateur
    try:
        # Lancer le script de calcul du bilan
        subprocess.run([sys.executable, CALCUL_SCRIPT], check=True, timeout=10)
        
        # Charger le bilan
        if os.path.exists(BILAN_JSON):
            with open(BILAN_JSON, "r", encoding="utf-8") as f:
                bilan_data = json.load(f)
                user_progress = bilan_data.get(username, 0)
        else:
            user_progress = 0
    except (subprocess.TimeoutExpired, subprocess.CalledProcessError, json.JSONDecodeError, FileNotFoundError, Exception):
        # En cas d'erreur, mettre à 0
        user_progress = 0
    
    return render_template("index.html", sourates=QURAN, username=username, user_progress=user_progress)


# Page sourate : lecture simple + cases à cocher
@app.route("/sourate/<int:id>", methods=["GET", "POST"])
def sourate(id):
    if "username" not in session:
        return redirect(url_for("login"))

    str_id = str(id)
    if str_id not in QURAN:
        return "Sourate non trouvée", 404

    sourate_info = QURAN[str_id]
    
    # Convertir les versets en liste de dictionnaires pour template
    verses = [{"numero": int(k), "texte": v} for k, v in sourate_info["versets"].items()]
    verses.sort(key=lambda x: x["numero"])

    # Charger la progression de l'utilisateur
    progress_data = load_progress()
    user_progress = progress_data.get(session["username"], {}).get(str_id, [])

    if request.method == "POST":
        checked = [
            int(key.split("_")[1])
            for key in request.form.keys()
            if key.startswith("checked_")
        ]
        if session["username"] not in progress_data:
            progress_data[session["username"]] = {}
        progress_data[session["username"]][str_id] = checked
        save_progress(progress_data)
        user_progress = checked

    return render_template(
        "sourate.html",
        sourate=sourate_info,
        verses=verses,
        progress=user_progress
    )
    
if __name__ == "__main__":
    # Mode développement uniquement - en production, utiliser Gunicorn
    app.run(debug=app.config['DEBUG'], host='0.0.0.0', port=3000)
