"""Routes salles - GMAO Collège"""
from datetime import date, datetime, timedelta
from flask import Blueprint, render_template, redirect, url_for, request, flash
from flask_login import login_required

from app_new.extensions import db
from app_new.core.models.college import Room, Zone, Building, RoomType, RoomProfile, RoomSurface, RoomSchedule
from app_new.core.models.equipment import Equipment

rooms_bp = Blueprint('rooms', __name__, template_folder='templates')


def _room_form_context(room=None):
    """Return all reference data used by the room form.

    The building list is deliberately loaded independently from the zone
    list.  Previously the GET route only supplied ``zones`` which left the
    required building select empty and made every room creation impossible.
    """
    return {
        'room': room,
        'buildings': Building.query.order_by(Building.name).all(),
        'zones': Zone.query.join(Building).order_by(Building.name, Zone.name).all(),
        'room_types': RoomType.query.order_by(RoomType.name).all(),
        'room_profiles': RoomProfile.query.order_by(RoomProfile.name).all(),
    }


@rooms_bp.route('/')
@login_required
def index():
    """Liste des salles."""
    zones_filter = request.args.getlist('zone') or None
    room_type_id = request.args.get('room_type', type=int)

    query = Room.query.join(Zone).join(Building)
    if zones_filter:
        query = query.filter(Zone.id.in_(zones_filter))
    if room_type_id:
        query = query.filter_by(room_type_id=room_type_id)
    rooms = query.order_by(Building.name, Zone.name, Room.name).all()
    zones = Zone.query.join(Building).order_by(Building.name, Zone.name).all()
    room_types = RoomType.query.order_by(RoomType.name).all()
    return render_template('equipments/rooms.html',
                          rooms=rooms, zones=zones, room_types=room_types,
                          selected_zones=[int(z) for z in zones_filter] if zones_filter else [])


@rooms_bp.route('/<int:id>')
@login_required
def detail(id):
    """Détail d'une salle."""
    room = Room.query.get_or_404(id)
    today = date.today()
    week_start = today - timedelta(days=today.weekday())
    # La vue salle consomme la résolution interne (manuel/Pronote/import),
    # afin de ne pas réafficher un créneau supplanté par la synchronisation.
    from app_new.core.services.room_planning import active_room_schedules
    courses = active_room_schedules(room.id, today)
    current_time = datetime.now().time()
    current_course = next(
        (course for course in courses
         if course.start_time <= current_time <= course.end_time),
        None,
    )
    next_course = next(
        (course for course in courses if course.start_time > current_time),
        None,
    )
    if current_course:
        room_status = {
            'status': 'occupee',
            'message': 'Salle actuellement occupée',
            'course': current_course,
            'next_occupied': None,
        }
    elif courses:
        room_status = {
            'status': 'libre',
            'message': 'Salle libre actuellement',
            'course': None,
            'next_occupied': next_course.start_time.strftime('%H:%M') if next_course else None,
        }
    else:
        room_status = {
            'status': 'inconnu',
            'message': "Aucun emploi du temps importé pour cette salle aujourd'hui.",
            'course': None,
            'next_occupied': None,
        }

    equipments = Equipment.query.filter(
        Equipment.room_id == room.id,
        Equipment.is_deleted.is_(False),
    ).order_by(Equipment.name, Equipment.individual_number).all()
    return render_template('equipments/room_detail.html',
                           room=room, equipments=equipments,
                           courses=courses, room_status=room_status, surfaces=room.surfaces)


@rooms_bp.route('/<int:id>/duplicate', methods=['GET', 'POST'])
@login_required
def duplicate(id):
    """Duplique explicitement un local, jamais son historique métier."""
    source = Room.query.get_or_404(id)
    if request.method == 'POST':
        name = (request.form.get('name') or '').strip()
        if not name:
            flash('Le nom du nouveau local est obligatoire.', 'danger')
            return render_template('equipments/room_duplicate.html', room=source), 400
        new_room = Room(name=name, code=request.form.get('code') or name,
                        building_id=source.building_id, zone_id=source.zone_id,
                        floor=source.floor, room_type_id=source.room_type_id,
                        room_profile_id=source.room_profile_id if request.form.get('copy_profile') else None)
        db.session.add(new_room)
        db.session.flush()
        if request.form.get('copy_surfaces'):
            for surface in source.surfaces:
                db.session.add(RoomSurface(room_id=new_room.id, surface_type=surface.surface_type,
                    material=surface.material, finish=surface.finish, label=surface.label, sort_order=surface.sort_order))
        if request.form.get('copy_equipment'):
            from app_new.core.services.equipment_creation import create_equipment
            for equipment in source.equipments:
                if equipment.is_deleted:
                    continue
                create_equipment(name=equipment.name, category_id=equipment.category_id,
                    lot_id=equipment.lot_id, room_id=new_room.id, quantity=equipment.quantity or 1,
                    is_group=equipment.is_group, tracked_individually=equipment.tracked_individually,
                    mobility=equipment.mobility, status=equipment.status,
                    management_mode=equipment.management_mode)
        db.session.commit()
        flash(f"Local '{new_room.name}' créé à partir de {source.name}.", 'success')
        return redirect(url_for('rooms.detail', id=new_room.id))
    return render_template('equipments/room_duplicate.html', room=source)


@rooms_bp.route('/<int:id>/surfaces', methods=['POST'])
@login_required
def add_surface(id):
    room = Room.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 sont obligatoires.', 'danger')
    else:
        db.session.add(RoomSurface(room_id=room.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 du local ajoutée.', 'success')
    return redirect(url_for('rooms.detail', id=room.id))


@rooms_bp.route('/new', methods=['GET', 'POST'])
@login_required
def create():
    """Créer une salle."""
    if request.method == 'POST':
        name = (request.form.get('name') or '').strip()
        building_id = request.form.get('building_id', type=int)
        zone_id = request.form.get('zone_id', type=int)
        building = db.session.get(Building, building_id) if building_id else None
        zone = db.session.get(Zone, zone_id) if zone_id else None
        errors = []
        if not name:
            errors.append('Le nom de la salle est obligatoire.')
        if not building:
            errors.append('Sélectionnez un bâtiment valide.')
        if zone and building and zone.building_id != building.id:
            errors.append('La zone sélectionnée n’appartient pas au bâtiment choisi.')
        if errors:
            for error in errors:
                flash(error, 'danger')
            context = _room_form_context()
            context['form_data'] = request.form
            return render_template('equipments/room_form.html', **context), 400
        room = Room(
            name=name,
            code=request.form.get('code') or None,
            zone_id=zone_id,
            building_id=building.id,
            room_type_id=request.form.get('room_type_id', type=int),
            room_profile_id=request.form.get('room_profile_id', type=int) or None,
            floor=request.form.get('floor', 0, type=int)
        )
        db.session.add(room)
        try:
            db.session.commit()
        except Exception:
            db.session.rollback()
            flash('Impossible d’enregistrer cette salle. Vérifiez les valeurs saisies.', 'danger')
            context = _room_form_context()
            context['form_data'] = request.form
            return render_template('equipments/room_form.html', **context), 400
        flash(f"Salle '{room.name}' créée.", 'success')
        return redirect(url_for('rooms.index'))

    context = _room_form_context()
    context['form_data'] = {}
    context['title'] = 'Nouvelle salle'
    return render_template('equipments/room_form.html', **context)


@rooms_bp.route('/bulk', methods=['GET', 'POST'])
@login_required
def bulk_create():
    """Création rapide de locaux similaires, sans imposer d'équipement."""
    context = _room_form_context()
    if request.method == 'POST':
        building_id = request.form.get('building_id', type=int)
        zone_id = request.form.get('zone_id', type=int)
        building = db.session.get(Building, building_id) if building_id else None
        zone = db.session.get(Zone, zone_id) if zone_id else None
        names = [line.strip() for line in (request.form.get('names') or '').splitlines() if line.strip()]
        if not building or (zone and (zone.building_id or (zone.building.id if zone.building else None)) != building.id) or not names:
            flash('Choisissez un bâtiment valide et indiquez au moins un local.', 'danger')
            return render_template('equipments/rooms_bulk.html', **context), 400
        if request.form.get('preview') == '1':
            existing = {room.name for room in Room.query.filter_by(building_id=building.id).all()}
            return render_template('equipments/rooms_bulk_preview.html', building=building, zone=zone,
                                   names=names, existing=existing,
                                   room_type_id=request.form.get('room_type_id', type=int),
                                   room_profile_id=request.form.get('room_profile_id', type=int) or None,
                                   floor=request.form.get('floor', 0, type=int))
        room_type_id = request.form.get('room_type_id', type=int)
        room_profile_id = request.form.get('room_profile_id', type=int) or None
        created = []
        existing = {room.name for room in Room.query.filter_by(building_id=building.id).all()}
        for name in names:
            if name in existing:
                continue
            created.append(Room(name=name, code=name, building_id=building.id,
                                zone_id=zone.id if zone else None,
                                room_type_id=room_type_id,
                                room_profile_id=room_profile_id,
                                floor=request.form.get('floor', 0, type=int)))
            existing.add(name)
        db.session.add_all(created)
        db.session.commit()
        flash(f'{len(created)} local(aux) créé(s). Aucun équipement n’a été ajouté automatiquement.', 'success')
        return redirect(url_for('rooms.index'))
    return render_template('equipments/rooms_bulk.html', **context)


@rooms_bp.route('/<int:id>/edit', methods=['GET', 'POST'])
@login_required
def edit(id):
    """Modifier une salle."""
    room = Room.query.get_or_404(id)

    if request.method == 'POST':
        name = (request.form.get('name') or '').strip()
        building_id = request.form.get('building_id', type=int)
        zone_id = request.form.get('zone_id', type=int)
        building = db.session.get(Building, building_id) if building_id else None
        zone = db.session.get(Zone, zone_id) if zone_id else None
        if not name or not building or (zone and zone.building_id != building.id):
            flash('Le nom, le bâtiment et une zone cohérente sont obligatoires.', 'danger')
            context = _room_form_context(room)
            context['form_data'] = request.form
            context['title'] = 'Modifier la salle'
            return render_template('equipments/room_form.html', **context), 400
        room.name = name
        room.code = request.form.get('code') or None
        room.zone_id = zone_id
        room.building_id = building.id
        room.room_type_id = request.form.get('room_type_id', type=int)
        room.room_profile_id = request.form.get('room_profile_id', type=int) or None
        room.floor = request.form.get('floor', 0, type=int)
        try:
            db.session.commit()
        except Exception:
            db.session.rollback()
            flash('Impossible d’enregistrer cette salle. Vérifiez les valeurs saisies.', 'danger')
            context = _room_form_context(room)
            context['form_data'] = request.form
            context['title'] = 'Modifier la salle'
            return render_template('equipments/room_form.html', **context), 400
        flash(f"Salle '{room.name}' mise à jour.", 'success')
        return redirect(url_for('rooms.index'))

    context = _room_form_context(room)
    context['form_data'] = {}
    context['title'] = 'Modifier la salle'
    return render_template('equipments/room_form.html', **context)


@rooms_bp.route('/<int:id>/delete', methods=['POST'])
@login_required
def delete(id):
    """Supprimer une salle."""
    room = Room.query.get_or_404(id)
    db.session.delete(room)
    db.session.commit()
    flash(f"Salle '{room.name}' supprimée.", 'success')
    return redirect(url_for('rooms.index'))
