"""Couverture métier du checkpoint B : profils sans création implicite."""
from app_new import db
from app_new.core.models.college import Building, Zone, Room, RoomProfile, RoomProfileItem
from app_new.core.models.equipment import Equipment
from app_new.core.services.equipment_creation import create_equipment
from app_new.core.models.equipment import EquipmentCategory
from app_new.core.models.planning import WorkSchedule
from time import perf_counter
import re


def test_room_profile_is_editable_and_application_uses_shared_service(authenticated_client, app):
    with app.app_context():
        building = Building(name="TEST_UI_020_B_BUILDING")
        db.session.add(building)
        db.session.flush()
        zone = Zone(name="TEST_UI_020_B_ZONE", building_id=building.id)
        category = EquipmentCategory(name="TEST_UI_020_B_LUMINAIRE")
        db.session.add_all([zone, category])
        db.session.flush()
        room = Room(name="TEST_UI_020_B101", code="TEST_UI_020_B101", building_id=building.id, zone_id=zone.id)
        db.session.add(room)
        db.session.flush()
        profile = RoomProfile(name="TEST_UI_020_B_CLASSE", description="Profil de validation")
        db.session.add(profile)
        db.session.flush()
        item = RoomProfileItem(profile_id=profile.id, label="Luminaire", category_id=category.id, quantity=10, is_group=True)
        db.session.add(item)
        db.session.commit()
        profile_id, room_id, item_id = profile.id, room.id, item.id
        assert RoomProfile.query.get(profile_id) is not None

    assert Equipment.query.filter_by(room_id=room_id).count() == 0
    with app.app_context():
        item = RoomProfileItem.query.get(item_id)
        created = create_equipment(name=item.label, category_id=item.category_id,
                                   room_id=room_id, quantity=4, is_group=item.is_group,
                                   create_schedule=False)
        db.session.commit()
        assert created.id is not None
        assert Equipment.query.filter_by(room_id=room_id).count() == 1
        assert Equipment.query.filter_by(room_id=room_id).one().quantity == 4


def test_bulk_room_can_reference_profile_without_creating_equipment(authenticated_client, app):
    with app.app_context():
        building = Building(name="TEST_UI_020_B_BULK_BUILDING")
        zone = Zone(name="TEST_UI_020_B_BULK_ZONE", building=building)
        profile = RoomProfile(name="TEST_UI_020_B_BULK_PROFILE")
        db.session.add_all([building, zone, profile])
        db.session.commit()
        building_id, zone_id, profile_id = building.id, zone.id, profile.id
    with app.app_context():
        rooms = [Room(name=name, code=name, building_id=building_id, zone_id=zone_id,
                      room_profile_id=profile_id, floor=1)
                 for name in ("TEST_UI_020_B101", "TEST_UI_020_B102")]
        db.session.add_all(rooms)
        db.session.commit()
        saved = Room.query.filter(Room.building_id == building_id, Room.room_profile_id == profile_id).all()
        assert len(saved) == 2
        assert Equipment.query.filter(Equipment.room_id.in_([room.id for room in saved])).count() == 0


def test_bulk_200_is_single_batch_and_does_not_duplicate(app):
    with app.app_context():
        building = Building(name="TEST_UI_020_BENCH_BUILDING")
        db.session.add(building); db.session.flush()
        names = [f"B{i:03d}" for i in range(200)]
        started = perf_counter()
        db.session.add_all([Room(name=name, code=name, building_id=building.id, floor=i % 4) for i, name in enumerate(names)])
        db.session.commit()
        elapsed = perf_counter() - started
        assert Room.query.filter(Room.building_id == building.id).count() == 200
        # The isolated fixture is torn down at session end; this assertion is
        # deliberately kept as a measurable smoke benchmark.
        assert elapsed < 10


def test_profile_preview_route_after_ui_creation(authenticated_client, app):
    created = authenticated_client.post('/room-profiles/new', data={'name': 'TEST_UI_B_HTTP_PROFILE_ROUTE'})
    assert created.status_code == 302
    profile_id = int(re.search(r'/room-profiles/(\d+)/edit', created.headers['Location']).group(1))
    item_response = authenticated_client.post(f'/room-profiles/{profile_id}/items', data={
        'label': 'TEST_UI_B_HTTP_LUMINAIRE', 'quantity': '2', 'is_group': '1', 'enabled_by_default': '1'
    })
    assert item_response.status_code == 302
    building_response = authenticated_client.post('/equipments/buildings/new', data={'name': 'TEST_UI_B_HTTP_ROUTE_BUILDING'})
    assert building_response.status_code == 303
    with app.app_context():
        db.session.remove(); building_id = Building.query.filter_by(name='TEST_UI_B_HTTP_ROUTE_BUILDING').one().id
    zone_response = authenticated_client.post(f'/equipments/buildings/{building_id}/zones', data={'name': 'TEST_UI_B_HTTP_ROUTE_ZONE'})
    assert zone_response.status_code == 303
    with app.app_context():
        db.session.remove(); zone_id = Zone.query.filter_by(name='TEST_UI_B_HTTP_ROUTE_ZONE').one().id
    room_response = authenticated_client.post('/equipments/rooms/new', data={
        'name': 'TEST_UI_B_HTTP_ROUTE_ROOM', 'code': 'UIB1', 'building_id': building_id,
        'zone_id': zone_id, 'room_profile_id': profile_id, 'floor': '1'
    })
    assert room_response.status_code == 302
    with app.app_context():
        db.session.remove()
        room = Room.query.filter_by(code='UIB1').first()
        assert room is not None
        room_id = room.id
        db.session.remove()
    preview = authenticated_client.get(f'/room-profiles/{profile_id}/preview?room_id={room_id}')
    assert preview.status_code == 200
    assert b'TEST_UI_B_HTTP_LUMINAIRE' in preview.data
    with app.app_context():
        db.session.remove()
        item_id = RoomProfileItem.query.filter_by(profile_id=profile_id).one().id
    applied = authenticated_client.post(f'/room-profiles/{profile_id}/preview', data={
        'room_ids': str(room_id), 'item_ids': str(item_id), f'quantity_{item_id}': '2', 'validate': '1'
    })
    assert applied.status_code == 302
    with app.app_context():
        db.session.remove()
        equipment = Equipment.query.filter_by(room_id=room_id, room_profile_item_id=item_id).one()
        assert equipment.quantity == 2
    # Une seconde application est idempotente.
    authenticated_client.post(f'/room-profiles/{profile_id}/preview', data={
        'room_ids': str(room_id), 'item_ids': str(item_id), f'quantity_{item_id}': '2', 'validate': '1'
    })
    with app.app_context():
        db.session.remove()
        assert Equipment.query.filter_by(room_id=room_id, room_profile_item_id=item_id).count() == 1
    # Modifier le profil ne modifie pas silencieusement l’équipement déjà créé.
    changed = authenticated_client.post(f'/room-profiles/{profile_id}/items/{item_id}/edit', data={
        'label': 'TEST_UI_B_HTTP_LUMINAIRE', 'quantity': '5', 'is_group': '1', 'enabled_by_default': '1'
    })
    assert changed.status_code == 302
    with app.app_context():
        db.session.remove()
        assert Equipment.query.filter_by(room_id=room_id, room_profile_item_id=item_id).one().quantity == 2


def test_work_schedule_ui_isolates_two_technicians(authenticated_client, app):
    def create_user(username, full_name):
        response = authenticated_client.post('/auth/users/new', data={
            'username': username, 'email': f'{username}@example.com', 'full_name': full_name,
            'password': 'Test-password-strong-123!', 'role': 'demandeur', 'role_ids': 'demandeur', 'is_active': 'y',
        })
        assert response.status_code == 302
        with app.app_context():
            db.session.remove(); return User.query.filter_by(username=username).one().id
    from app_new.core.models.user import User
    tech_a = create_user('TEST_UI_B_TECH_A', 'TEST_UI_B_TECH_A')
    tech_b = create_user('TEST_UI_B_TECH_B', 'TEST_UI_B_TECH_B')
    data_a = {'user_id': tech_a, 'academic_year': '2026'}
    data_b = {'user_id': tech_b, 'academic_year': '2026'}
    for data, start, end, lunch_start, lunch_end in ((data_a, '08:00', '17:00', '12:00', '13:30'), (data_b, '07:00', '15:30', '11:30', '12:30')):
        data.update({'start_0': start, 'end_0': end, 'lunch_start_0': lunch_start, 'lunch_end_0': lunch_end})
        response = authenticated_client.post('/planning/work-schedules', data=data)
        assert response.status_code == 200
    with app.app_context():
        db.session.remove()
        a = WorkSchedule.query.filter_by(user_id=tech_a, day_of_week=0, academic_year=2026, is_active=True).one()
        b = WorkSchedule.query.filter_by(user_id=tech_b, day_of_week=0, academic_year=2026, is_active=True).one()
        assert (a.start_time.hour, a.end_time.hour, a.lunch_start.hour, a.lunch_end.hour) == (8, 17, 12, 13)
        assert (b.start_time.hour, b.end_time.hour, b.lunch_start.hour, b.lunch_end.hour) == (7, 15, 11, 12)


def test_configuration_center_renders_optional_states(authenticated_client):
    response = authenticated_client.get('/configuration/')
    assert response.status_code == 200
    assert b'ESSENTIEL' in response.data
    assert b'COMPTEURS' in response.data
    assert b'CARTOGRAPHIE TECHNIQUE' in response.data
    assert b'Facultatif' in response.data


def test_room_duplication_http_creates_new_identity(authenticated_client, app):
    building_response = authenticated_client.post('/equipments/buildings/new', data={'name': 'TEST_UI_B_DUP_BUILDING'})
    assert building_response.status_code == 303
    with app.app_context():
        db.session.remove(); building_id = Building.query.filter_by(name='TEST_UI_B_DUP_BUILDING').one().id
    room_response = authenticated_client.post('/equipments/rooms/new', data={
        'name': 'TEST_UI_B_DUP_SOURCE', 'code': 'DUP1', 'building_id': building_id, 'floor': '1'
    })
    assert room_response.status_code == 302
    with app.app_context():
        db.session.remove(); source_id = Room.query.filter_by(code='DUP1').one().id
    duplicate_response = authenticated_client.post(f'/equipments/rooms/{source_id}/duplicate', data={
        'name': 'TEST_UI_B_DUP_COPY', 'copy_profile': '1', 'copy_surfaces': '1'
    })
    assert duplicate_response.status_code == 302
    with app.app_context():
        db.session.remove()
        assert Room.query.filter_by(name='TEST_UI_B_DUP_COPY').count() == 1
