from flask import Blueprint, render_template, request, redirect, url_for, flash
from flask_login import login_required

from app_new.extensions import db
from app_new.core.models.college import RoomProfile, RoomProfileItem, RoomType, Room, RoomSurface
from app_new.core.models.equipment import EquipmentCategory, Equipment
from app_new.core.models.maintenance import Lot
from app_new.core.services.equipment_creation import create_equipment

room_profiles_bp = Blueprint("room_profiles", __name__, template_folder="templates")


def _context(profile=None):
    return {
        "profile": profile,
        "room_types": RoomType.query.order_by(RoomType.name).all(),
        "categories": EquipmentCategory.query.order_by(EquipmentCategory.name).all(),
        "lots": Lot.query.order_by(Lot.name).all(),
    }


@room_profiles_bp.route("/")
@login_required
def index():
    return render_template("room_profiles/index.html", profiles=RoomProfile.query.order_by(RoomProfile.name).all())


@room_profiles_bp.route("/new", methods=["GET", "POST"])
@login_required
def new():
    if request.method == "POST":
        name = (request.form.get("name") or "").strip()
        if not name:
            flash("Le nom du profil est obligatoire.", "danger")
            return render_template("room_profiles/form.html", title="Nouveau profil", **_context()), 400
        if RoomProfile.query.filter(db.func.lower(RoomProfile.name) == name.lower()).first():
            flash("Un profil porte déjà ce nom.", "danger")
            return render_template("room_profiles/form.html", title="Nouveau profil", **_context()), 400
        profile = RoomProfile(
            name=name,
            description=(request.form.get("description") or "").strip() or None,
            room_type_id=request.form.get("room_type_id", type=int) or None,
        )
        db.session.add(profile)
        db.session.commit()
        flash("Profil créé. Ajoutez ses propositions puis prévisualisez avant toute création.", "success")
        return redirect(url_for("room_profiles.edit", id=profile.id))
    return render_template("room_profiles/form.html", title="Nouveau profil", **_context())


@room_profiles_bp.route("/<int:id>/edit", methods=["GET", "POST"])
@login_required
def edit(id):
    profile = RoomProfile.query.get_or_404(id)
    if request.method == "POST":
        profile.name = (request.form.get("name") or "").strip()
        profile.description = (request.form.get("description") or "").strip() or None
        profile.room_type_id = request.form.get("room_type_id", type=int) or None
        if not profile.name:
            flash("Le nom du profil est obligatoire.", "danger")
            return render_template("room_profiles/form.html", title="Modifier le profil", **_context(profile)), 400
        db.session.commit()
        flash("Profil mis à jour.", "success")
        return redirect(url_for("room_profiles.edit", id=profile.id))
    return render_template("room_profiles/form.html", title="Modifier le profil", **_context(profile))


@room_profiles_bp.route("/<int:id>/items", methods=["POST"])
@login_required
def add_item(id):
    profile = RoomProfile.query.get_or_404(id)
    label = (request.form.get("label") or "").strip()
    quantity = request.form.get("quantity", 1, type=int)
    if not label or not quantity or quantity < 1:
        flash("Libellé et quantité positive sont obligatoires.", "danger")
        return redirect(url_for("room_profiles.edit", id=id))
    item = RoomProfileItem(
        profile_id=profile.id,
        label=label,
        category_id=request.form.get("category_id", type=int) or None,
        lot_id=request.form.get("lot_id", type=int) or None,
        quantity=quantity,
        is_group=request.form.get("is_group") == "1",
        enabled_by_default=request.form.get("enabled_by_default") == "1",
        sort_order=request.form.get("sort_order", 0, type=int),
    )
    db.session.add(item)
    db.session.commit()
    flash("Proposition ajoutée au profil.", "success")
    return redirect(url_for("room_profiles.edit", id=id))


@room_profiles_bp.route("/<int:profile_id>/items/<int:item_id>/delete", methods=["POST"])
@login_required
def delete_item(profile_id, item_id):
    item = RoomProfileItem.query.filter_by(id=item_id, profile_id=profile_id).first_or_404()
    db.session.delete(item)
    db.session.commit()
    flash("Proposition retirée du profil.", "success")
    return redirect(url_for("room_profiles.edit", id=profile_id))


@room_profiles_bp.route("/<int:profile_id>/items/<int:item_id>/edit", methods=["POST"])
@login_required
def edit_item(profile_id, item_id):
    item = RoomProfileItem.query.filter_by(id=item_id, profile_id=profile_id).first_or_404()
    label = (request.form.get("label") or item.label).strip()
    quantity = request.form.get("quantity", item.quantity, type=int)
    if not label or not quantity or quantity < 1:
        flash("Libellé et quantité positive sont obligatoires.", "danger")
        return redirect(url_for("room_profiles.edit", id=profile_id))
    item.label = label
    item.quantity = quantity
    item.category_id = request.form.get("category_id", type=int) or None
    item.lot_id = request.form.get("lot_id", type=int) or None
    item.is_group = request.form.get("is_group") == "1"
    item.enabled_by_default = request.form.get("enabled_by_default") == "1"
    db.session.commit()
    flash("Proposition du profil mise à jour. Les locaux déjà appliqués restent inchangés.", "success")
    return redirect(url_for("room_profiles.edit", id=profile_id))


@room_profiles_bp.route("/<int:id>/preview", methods=["GET", "POST"])
@login_required
def preview(id):
    profile = RoomProfile.query.get(id)
    if profile is None:
        from flask import abort
        abort(404)
    room_ids = request.form.getlist("room_ids", type=int) if request.method == "POST" else request.args.getlist("room_id", type=int)
    rooms = Room.query.filter(Room.id.in_(room_ids)).order_by(Room.name).all() if room_ids else []
    items = [item for item in profile.items if item.enabled_by_default]
    existing = {(room.id, item.id): sum((equipment.quantity or 1) for equipment in Equipment.query.filter_by(
        room_id=room.id, room_profile_item_id=item.id, is_deleted=False).all())
        for room in rooms for item in items}
    if request.method == "POST" and request.form.get("validate") == "1":
        selected = {int(value) for value in request.form.getlist("item_ids") if value.isdigit()}
        if not rooms or not selected:
            flash("Sélectionnez au moins un local et une proposition.", "danger")
            return render_template("room_profiles/preview.html", profile=profile, rooms=rooms, items=items, existing=existing)
        created = 0
        for room in rooms:
            for item in items:
                if item.id not in selected:
                    continue
                quantity = request.form.get(f"quantity_{item.id}", item.quantity, type=int)
                if quantity < 1:
                    continue
                quantity = max(quantity - existing.get((room.id, item.id), 0), 0)
                if not quantity:
                    continue
                create_equipment(
                    name=item.label,
                    category_id=item.category_id,
                    lot_id=item.lot_id,
                    room_id=room.id,
                    quantity=quantity,
                    is_group=item.is_group,
                    room_profile_item_id=item.id,
                )
                created += 1
        db.session.commit()
        flash(f"{created} proposition(s) appliquée(s). Les équipements ont été créés via le service commun.", "success")
        return redirect(url_for("rooms.index"))
    return render_template("room_profiles/preview.html", profile=profile, rooms=rooms, items=items, existing=existing)


@room_profiles_bp.route("/<int:id>/surfaces", methods=["POST"])
@login_required
def add_surface(id):
    profile = RoomProfile.query.get_or_404(id)
    surface_type = request.form.get("surface_type")
    material = (request.form.get("material") or "").strip()
    if surface_type not in {"mur", "sol", "plafond", "autre"} or not material:
        flash("Type et matériau de surface obligatoires.", "danger")
        return redirect(url_for("room_profiles.edit", id=id))
    db.session.add(RoomSurface(profile_id=profile.id, surface_type=surface_type, material=material,
                                finish=(request.form.get("finish") or "").strip() or None,
                                label=(request.form.get("label") or "").strip() or None))
    db.session.commit()
    flash("Composition proposée ajoutée.", "success")
    return redirect(url_for("room_profiles.edit", id=id))
