from flask import Blueprint, flash, redirect, render_template, request, url_for, current_app
from flask_login import login_required
from sqlalchemy.exc import IntegrityError, OperationalError

from app.helpers import admin_required, copropriete_ids_from_public_ids, set_user_coproprietes
from app.models import Copropriete, User, UserCopropriete, db

bp = Blueprint("admin", __name__, url_prefix="/admin")


def _all_coproprietes():
    return Copropriete.query_actifs().order_by(Copropriete.nom).all()


def _user_copropriete_ids(user: User) -> list[int]:
    return [uc.copropriete_id for uc in user.coproprietes]


@bp.route("/utilisateurs")
@login_required
@admin_required
def utilisateurs_liste():
    users = User.query.order_by(User.username).all()
    return render_template("admin/utilisateurs_liste.html", users=users)


@bp.route("/utilisateurs/nouveau", methods=["GET", "POST"])
@login_required
@admin_required
def utilisateur_nouveau():
    coproprietes = _all_coproprietes()
    if request.method == "POST":
        username = request.form.get("username", "").strip()
        password = request.form.get("password", "")
        password2 = request.form.get("password2", "")
        is_admin = bool(request.form.get("is_admin"))
        copro_ids = copropriete_ids_from_public_ids(request.form.getlist("copropriete_ids"))

        if not username:
            flash("L'identifiant est obligatoire.", "danger")
        elif User.query.filter_by(username=username).first():
            flash("Cet identifiant existe déjà.", "danger")
        elif len(password) < 6:
            flash("Le mot de passe doit faire au moins 6 caractères.", "danger")
        elif password != password2:
            flash("Les mots de passe ne correspondent pas.", "danger")
        else:
            user = User(username=username, is_admin=is_admin)
            user.set_password(password)
            db.session.add(user)
            try:
                db.session.flush()
                set_user_coproprietes(user.id, copro_ids)
                db.session.commit()
            except IntegrityError:
                db.session.rollback()
                flash("Cet identifiant existe déjà dans cette base.", "danger")
            except OperationalError as exc:
                db.session.rollback()
                flash(
                    "Impossible d'écrire dans la base (fichier verrouillé ou indisponible). "
                    "Réessayez dans quelques secondes.",
                    "danger",
                )
                current_app.logger.warning("Création utilisateur : %s", exc)
            else:
                flash(f"Utilisateur « {username} » créé.", "success")
                return redirect(url_for("admin.utilisateurs_liste"))

    return render_template(
        "admin/utilisateur_form.html",
        user=None,
        coproprietes=coproprietes,
        selected_copro_ids=[],
    )


@bp.route("/utilisateurs/<uuid:user_id>/edit", methods=["GET", "POST"])
@login_required
@admin_required
def utilisateur_edit(user_id):
    user = User.query.filter_by(public_id=str(user_id)).first()
    if not user:
        flash("Utilisateur introuvable.", "danger")
        return redirect(url_for("admin.utilisateurs_liste"))

    coproprietes = _all_coproprietes()

    if request.method == "POST":
        is_admin = bool(request.form.get("is_admin"))
        is_active = bool(request.form.get("is_active"))
        copro_ids = copropriete_ids_from_public_ids(request.form.getlist("copropriete_ids"))
        new_password = request.form.get("password", "")
        new_password2 = request.form.get("password2", "")

        if new_password or new_password2:
            if len(new_password) < 6:
                flash("Le mot de passe doit faire au moins 6 caractères.", "danger")
                return render_template(
                    "admin/utilisateur_form.html",
                    user=user,
                    coproprietes=coproprietes,
                    selected_copro_ids=_user_copropriete_ids(user),
                )
            if new_password != new_password2:
                flash("Les mots de passe ne correspondent pas.", "danger")
                return render_template(
                    "admin/utilisateur_form.html",
                    user=user,
                    coproprietes=coproprietes,
                    selected_copro_ids=_user_copropriete_ids(user),
                )
            user.set_password(new_password)

        # Empêcher de se retirer soi-même les droits admin / actif
        from flask_login import current_user

        if user.id == current_user.id:
            user.is_admin = True
            user.is_active = True
        else:
            user.is_admin = is_admin
            user.is_active = is_active

        set_user_coproprietes(user.id, copro_ids)
        db.session.commit()
        flash(f"Utilisateur « {user.username} » mis à jour.", "success")
        return redirect(url_for("admin.utilisateurs_liste"))

    return render_template(
        "admin/utilisateur_form.html",
        user=user,
        coproprietes=coproprietes,
        selected_copro_ids=_user_copropriete_ids(user),
    )
