from flask import Blueprint, flash, redirect, render_template, request, url_for
from flask_login import login_required

from app.constants import ROLE_LABELS, ROLES_LOT
from app.helpers import copropriete_required, get_by_public_id
from app.models import Adresse, Email, Lot, LotPersonneRole, Personne, Telephone, db
from app.phone import normalize_phone
from app.soft_delete import STATUT_ACTIF

bp = Blueprint("personnes", __name__, url_prefix="/personnes")


def _parse_contacts(form, personne: Personne) -> None:
    for t in personne.telephones:
        db.session.delete(t)
    for e in personne.emails:
        db.session.delete(e)
    for a in personne.adresses:
        db.session.delete(a)

    for i in range(int(form.get("tel_count", 0) or 0)):
        numero = normalize_phone(form.get(f"tel_numero_{i}", "").strip())
        if numero:
            db.session.add(
                Telephone(
                    personne=personne,
                    libelle=form.get(f"tel_libelle_{i}", "").strip(),
                    numero=numero,
                )
            )

    for i in range(int(form.get("email_count", 0) or 0)):
        adresse = form.get(f"email_adresse_{i}", "").strip()
        if adresse:
            db.session.add(
                Email(
                    personne=personne,
                    libelle=form.get(f"email_libelle_{i}", "").strip(),
                    adresse=adresse,
                )
            )

    for i in range(int(form.get("addr_count", 0) or 0)):
        ligne1 = form.get(f"addr_ligne1_{i}", "").strip()
        if ligne1:
            db.session.add(
                Adresse(
                    personne=personne,
                    libelle=form.get(f"addr_libelle_{i}", "").strip(),
                    ligne1=ligne1,
                    ligne2=form.get(f"addr_ligne2_{i}", "").strip(),
                    code_postal=form.get(f"addr_cp_{i}", "").strip(),
                    ville=form.get(f"addr_ville_{i}", "").strip(),
                )
            )


def _filtrer_personnes(copropriete, q: str, afficher_supprimes: bool, roles_filtre: list[str]):
    if afficher_supprimes:
        query = Personne.query_archives().filter_by(copropriete_id=copropriete.id)
    else:
        query = Personne.query_actifs().filter_by(copropriete_id=copropriete.id)
    if q:
        like = f"%{q}%"
        query = query.filter(
            db.or_(
                Personne.nom.ilike(like),
                Personne.prenom.ilike(like),
                Personne.raison_sociale.ilike(like),
            )
        )
    if roles_filtre:
        personnes_avec_role = (
            db.session.query(LotPersonneRole.personne_id)
            .join(Lot)
            .filter(
                Lot.copropriete_id == copropriete.id,
                LotPersonneRole.statut == STATUT_ACTIF,
                LotPersonneRole.date_fin.is_(None),
                LotPersonneRole.role.in_(roles_filtre),
            )
            .distinct()
        )
        query = query.filter(Personne.id.in_(personnes_avec_role))
    return query.order_by(Personne.nom, Personne.prenom).all()


def _liste_context(copropriete, q, afficher_supprimes, roles_filtre, personnes):
    return {
        "personnes": personnes,
        "q": q,
        "copropriete": copropriete,
        "afficher_supprimes": afficher_supprimes,
        "roles_filtre": roles_filtre,
        "roles_lot": ROLES_LOT,
        "role_labels": ROLE_LABELS,
    }


@bp.route("/")
@login_required
@copropriete_required
def liste(copropriete):
    q = request.args.get("q", "").strip()
    afficher_supprimes = request.args.get("supprimes") == "1"
    roles_filtre = [r for r in request.args.getlist("role") if r in ROLES_LOT]
    personnes = _filtrer_personnes(copropriete, q, afficher_supprimes, roles_filtre)
    ctx = _liste_context(copropriete, q, afficher_supprimes, roles_filtre, personnes)
    if request.args.get("fragment") == "1":
        return render_template("personnes/_liste_resultats.html", **ctx)
    return render_template("personnes/liste.html", **ctx)


@bp.route("/nouveau", methods=["GET", "POST"])
@login_required
@copropriete_required
def nouveau(copropriete):
    if request.method == "POST":
        nom = request.form.get("nom", "").strip()
        raison_sociale = request.form.get("raison_sociale", "").strip()
        if not nom and not raison_sociale:
            flash("Le nom ou la raison sociale est obligatoire.", "danger")
        else:
            personne = Personne(
                copropriete_id=copropriete.id,
                civilite=request.form.get("civilite", "").strip(),
                nom=nom or raison_sociale,
                prenom=request.form.get("prenom", "").strip(),
                raison_sociale=raison_sociale,
                notes=request.form.get("notes", "").strip(),
            )
            db.session.add(personne)
            db.session.flush()
            _parse_contacts(request.form, personne)
            db.session.commit()
            flash("Personne créée.", "success")
            return redirect(url_for("personnes.detail", personne_id=personne.public_id))
    return render_template("personnes/form.html", personne=None, copropriete=copropriete)


@bp.route("/<uuid:personne_id>")
@login_required
@copropriete_required
def detail(copropriete, personne_id):
    personne = get_by_public_id(
        Personne, personne_id, copropriete_id=copropriete.id
    )
    return render_template(
        "personnes/detail.html",
        personne=personne,
        copropriete=copropriete,
        role_labels=ROLE_LABELS,
    )


@bp.route("/<uuid:personne_id>/edit", methods=["GET", "POST"])
@login_required
@copropriete_required
def edit(copropriete, personne_id):
    personne = get_by_public_id(
        Personne, personne_id, copropriete_id=copropriete.id
    )
    if personne.est_supprime:
        flash("Cette personne est supprimée. Restaurez-la pour la modifier.", "warning")
        return redirect(url_for("personnes.detail", personne_id=personne.public_id))
    if request.method == "POST":
        nom = request.form.get("nom", "").strip()
        raison_sociale = request.form.get("raison_sociale", "").strip()
        if not nom and not raison_sociale:
            flash("Le nom ou la raison sociale est obligatoire.", "danger")
        else:
            personne.civilite = request.form.get("civilite", "").strip()
            personne.nom = nom or raison_sociale
            personne.prenom = request.form.get("prenom", "").strip()
            personne.raison_sociale = raison_sociale
            personne.notes = request.form.get("notes", "").strip()
            _parse_contacts(request.form, personne)
            db.session.commit()
            flash("Personne mise à jour.", "success")
            return redirect(url_for("personnes.detail", personne_id=personne.public_id))
    return render_template(
        "personnes/form.html", personne=personne, copropriete=copropriete
    )


@bp.route("/<uuid:personne_id>/supprimer", methods=["POST"])
@login_required
@copropriete_required
def supprimer(copropriete, personne_id):
    personne = get_by_public_id(
        Personne, personne_id, copropriete_id=copropriete.id
    )
    if not personne.est_supprime:
        personne.marquer_supprime()
        db.session.commit()
        flash("Personne supprimée.", "info")
    return redirect(url_for("personnes.liste"))


@bp.route("/<uuid:personne_id>/restaurer", methods=["POST"])
@login_required
@copropriete_required
def restaurer(copropriete, personne_id):
    personne = get_by_public_id(
        Personne, personne_id, copropriete_id=copropriete.id
    )
    if not personne.est_supprime:
        flash("Cette personne est déjà active.", "info")
    else:
        personne.restaurer()
        db.session.commit()
        flash("Personne restaurée.", "success")
    return redirect(url_for("personnes.detail", personne_id=personne.public_id))
