from pathlib import Path


def test_build_commit_prefers_deployment_environment(monkeypatch):
    from app_new.core.build_info import get_build_commit

    monkeypatch.setenv('GIT_COMMIT', 'commit-deploye-test')
    monkeypatch.setenv('GIT_VERSION', 'version-commit')
    monkeypatch.setenv('COMMIT_SHA', 'autre-commit')
    assert get_build_commit() == 'commit-deploye-test'


def test_setup_pages_display_build_commit(client, monkeypatch, tmp_path):
    from app_new.core.routes import setup_wizard

    monkeypatch.setattr(setup_wizard, 'DATA_DIR', str(tmp_path))
    monkeypatch.setenv('GIT_COMMIT', 'commit-visible-test')
    client.application.config['GIT_COMMIT'] = 'commit-visible-test'
    token = 'test-setup-token-with-at-least-32-characters'

    response = client.get(f'/setup-wizard/?token={token}')
    assert response.status_code == 302
    response = client.get('/setup-wizard/')
    assert b'commit-visible-test' in response.data

    Path(tmp_path, '.setup_complete').write_text('complete', encoding='utf-8')
    response = client.get('/setup-wizard/')
    assert response.status_code == 200
    assert b'commit-visible-test' in response.data


def test_login_page_does_not_disclose_demo_passwords(client):
    response = client.get('/auth/login')
    assert response.status_code == 200
    assert b'admin</code>' not in response.data
    assert b'admin</code></td><td><code>admin' not in response.data


def test_login_rejects_external_next_url(client, admin_user):
    response = client.post(
        '/auth/login?next=//example.net',
        data={'username': admin_user['username'], 'password': admin_user['password']},
    )
    assert response.status_code == 302
    assert 'example.net' not in response.headers['Location']


def test_setup_requires_token(client, monkeypatch, tmp_path):
    from app_new.core.routes import setup_wizard

    monkeypatch.setattr(setup_wizard, 'DATA_DIR', str(tmp_path))
    assert client.get('/setup-wizard/').status_code == 403
    assert client.get('/setup-wizard/?token=invalid').status_code == 403


def test_setup_token_is_removed_from_url(client, monkeypatch, tmp_path):
    from app_new.core.routes import setup_wizard

    monkeypatch.setattr(setup_wizard, 'DATA_DIR', str(tmp_path))
    token = 'test-setup-token-with-at-least-32-characters'
    response = client.get(f'/setup-wizard/?token={token}')
    assert response.status_code == 302
    assert 'token=' not in response.headers['Location']
    assert client.get('/setup-wizard/').status_code == 200


def test_completed_setup_rejects_mutation(client, monkeypatch, tmp_path):
    from app_new.core.routes import setup_wizard

    monkeypatch.setattr(setup_wizard, 'DATA_DIR', str(tmp_path))
    Path(tmp_path, '.setup_complete').write_text('complete', encoding='utf-8')
    response = client.post('/setup-wizard/api/step/1', json={
        'username': 'new-admin',
        'password': 'a-strong-password',
    })
    assert response.status_code == 403


def _authorize_setup(client, monkeypatch, tmp_path):
    from app_new.core.routes import setup_wizard

    monkeypatch.setattr(setup_wizard, 'DATA_DIR', str(tmp_path))
    token = 'test-setup-token-with-at-least-32-characters'
    response = client.get(f'/setup-wizard/?token={token}')
    assert response.status_code == 302


def test_setup_updates_buildings_without_deleting_existing(client, app, monkeypatch, tmp_path):
    from app_new import db
    from app_new.core.models.college import Building

    _authorize_setup(client, monkeypatch, tmp_path)
    with app.app_context():
        existing = Building(name='Bâtiment conservé', description='Ancienne description')
        untouched = Building(name='Bâtiment hors formulaire')
        db.session.add_all([existing, untouched])
        db.session.commit()
        existing_id, untouched_id = existing.id, untouched.id

    response = client.post('/setup-wizard/api/step/3', json={'buildings': [
        {'id': existing_id, 'name': 'Bâtiment conservé', 'description': 'Mise à jour'},
        {'name': 'Nouveau bâtiment', 'description': ''},
    ]})
    assert response.status_code == 200

    with app.app_context():
        assert db.session.get(Building, existing_id).description == 'Mise à jour'
        assert db.session.get(Building, untouched_id) is not None
        assert Building.query.filter_by(name='Nouveau bâtiment').count() == 1


def test_setup_creates_zones_and_rooms_with_valid_links(client, app, monkeypatch, tmp_path):
    from app_new import db
    from app_new.core.models.college import Building, Room, Zone

    _authorize_setup(client, monkeypatch, tmp_path)
    with app.app_context():
        building = Building(name='Bâtiment relations wizard')
        db.session.add(building)
        db.session.commit()
        building_id = building.id

    zone_response = client.post('/setup-wizard/api/step/4', json={'zones': [
        {'name': 'Zone wizard', 'building_id': building_id},
    ]})
    assert zone_response.status_code == 200
    zone_id = zone_response.get_json()['zones'][0]['id']

    room_response = client.post('/setup-wizard/api/step/5', json={'rooms': [
        {'name': 'Salle wizard', 'code': 'W01', 'building_id': building_id, 'zone_id': zone_id, 'floor': 1},
    ]})
    assert room_response.status_code == 200
    with app.app_context():
        zone = db.session.get(Zone, zone_id)
        room = Room.query.filter_by(name='Salle wizard').one()
        assert zone.building_id == building_id
        assert room.building_id == building_id
        assert room.zone_id == zone_id
        assert room.floor == 1


def test_setup_imports_embedded_lot_catalog_idempotently(client, app, monkeypatch, tmp_path):
    from app_new.core.models.equipment import EquipmentCategory
    from app_new.core.models.maintenance import Lot, LotTask
    from app_new.core.setup_catalog import EQUIPMENT_CATEGORIES, LOTS, LOT_TASKS

    _authorize_setup(client, monkeypatch, tmp_path)
    first = client.post('/setup-wizard/api/step/6', json={})
    second = client.post('/setup-wizard/api/step/6', json={})
    assert first.status_code == second.status_code == 200
    assert first.get_json()['categories_count'] == len(EQUIPMENT_CATEGORIES)
    assert first.get_json()['lots_count'] == len(LOTS)
    assert first.get_json()['lot_tasks_count'] == len(LOT_TASKS)

    with app.app_context():
        for name in EQUIPMENT_CATEGORIES:
            assert EquipmentCategory.query.filter_by(name=name).count() == 1
        for name, category_name in LOTS:
            lot = Lot.query.filter_by(name=name).one()
            assert lot.category.name == category_name
        assert LotTask.query.count() == len(LOT_TASKS)


def test_setup_saves_exact_work_days_inside_school_holidays(client, app, monkeypatch, tmp_path):
    from datetime import date, time
    from app_new.core.models.planning import CollegeClosure, ClosureWorkDay
    from app_new.core.services.planning_service import PlanningService

    _authorize_setup(client, monkeypatch, tmp_path)
    response = client.post('/setup-wizard/api/step/7', json={
        'zone': 'C',
        'annee': 2026,
        'import_vacances': True,
        'import_feries': True,
        'vacation_periods': [{
            'name': 'Petites vacances test wizard',
            'start_date': '2026-10-19',
            'end_date': '2026-10-30',
            'work_days': [
                {
                    'work_date': '2026-10-19', 'start_time': '08:00', 'end_time': '16:00',
                    'lunch_start': '12:00', 'lunch_end': '12:45', 'notes': 'Début des vacances',
                },
                {
                    'work_date': '2026-10-30', 'start_time': '09:15', 'end_time': '13:30',
                    'lunch_start': '', 'lunch_end': '', 'notes': 'Fin des vacances',
                },
            ],
        }],
    })
    assert response.status_code == 200

    with app.app_context():
        closure = CollegeClosure.query.filter_by(name='Petites vacances test wizard').one()
        assert closure.work_hours_type == 'none'
        assert ClosureWorkDay.query.filter_by(closure_id=closure.id).count() == 2
        assert PlanningService.get_working_hours(date(2026, 10, 20)) is None
        assert PlanningService.get_working_hours(date(2026, 10, 19)) == (
            time(8, 0), time(16, 0), time(12, 0), time(12, 45)
        )
        assert PlanningService.get_working_hours(date(2026, 10, 30)) == (
            time(9, 15), time(13, 30), None, None
        )


def test_setup_rejects_work_day_outside_vacation_period(client, monkeypatch, tmp_path):
    _authorize_setup(client, monkeypatch, tmp_path)
    response = client.post('/setup-wizard/api/step/7', json={
        'zone': 'C', 'annee': 2026,
        'vacation_periods': [{
            'name': 'Vacances invalides', 'start_date': '2026-12-20', 'end_date': '2027-01-03',
            'work_days': [{'work_date': '2026-12-10', 'start_time': '08:00', 'end_time': '16:00'}],
        }],
    })
    assert response.status_code == 400
    assert 'hors de la période' in response.get_json()['error']
