import pytest
from datetime import datetime
from app import app, mysql, PERMISSION_KEYS

@pytest.fixture(scope="module", autouse=True)
def app_context():
    with app.app_context():
        yield

@pytest.fixture
def client():
    app.config['TESTING'] = True
    app.config['WTF_CSRF_ENABLED'] = False
    with app.test_client() as client:
        with client.session_transaction() as sess:
            sess['user_id'] = 9999
            sess['username'] = 'TEST_ADMIN'
            sess['user_role'] = 'SUPER ADMIN'
            sess['notif_config'] = '{}'
        yield client

def test_roles_list_empty_message(client):
    # Temporarily rename/clear roles to simulate empty state
    cursor = mysql.connection.cursor()
    cursor.execute("CREATE TEMPORARY TABLE temp_roles SELECT * FROM roles")
    cursor.execute("DELETE FROM roles")
    mysql.connection.commit()
    cursor.close()

    response = client.get('/roles')
    html = response.data.decode('utf-8')
    
    # Restore roles
    cursor = mysql.connection.cursor()
    cursor.execute("INSERT INTO roles SELECT * FROM temp_roles")
    cursor.execute("DROP TEMPORARY TABLE temp_roles")
    mysql.connection.commit()
    cursor.close()

    assert "Aucun rôle trouvé" in html or "La table des rôles n'est pas encore initialisée" in html

def test_roles_badges(client):
    # Check custom role vs built-in badges
    cursor = mysql.connection.cursor()
    cursor.execute("SELECT id FROM roles WHERE name = 'SUPER ADMIN'")
    sa_role = cursor.fetchone()
    
    # Insert custom role
    cursor.execute("INSERT INTO roles (name, is_builtin) VALUES ('TEST_ROLE_BADGE_TEMP', 0)")
    mysql.connection.commit()
    cursor.execute("SELECT id FROM roles WHERE name = 'TEST_ROLE_BADGE_TEMP'")
    custom_role = cursor.fetchone()
    cursor.close()

    response = client.get('/roles')
    html = response.data.decode('utf-8')

    # Cleanup
    cursor = mysql.connection.cursor()
    cursor.execute("DELETE FROM roles WHERE name = 'TEST_ROLE_BADGE_TEMP'")
    mysql.connection.commit()
    cursor.close()

    assert "Intégré" in html
    assert "Personnalisé" in html

def test_role_add_form_notification_toggles(client):
    response = client.get('/roles/ajouter')
    html = response.data.decode('utf-8')
    
    # Count occurrence of "switch_notif_" checkboxes
    assert html.count('name="notif_') == 6

def test_role_edit_form_select_all_buttons(client):
    cursor = mysql.connection.cursor()
    cursor.execute("SELECT id FROM roles WHERE name = 'STM' LIMIT 1")
    role = cursor.fetchone()
    cursor.close()

    response = client.get(f'/roles/{role["id"]}/modifier')
    html = response.data.decode('utf-8')

    assert "Tout sélectionner" in html or "toggleCategory" in html

def test_user_edit_form_reset_notif_button(client):
    cursor = mysql.connection.cursor()
    cursor.execute("SELECT id FROM user LIMIT 1")
    user = cursor.fetchone()
    cursor.close()

    if user:
        response = client.get(f'/utilisateurs/modifier/{user["id"]}')
        html = response.data.decode('utf-8')
        assert "Réinitialiser aux défauts" in html or "resetNotifConfig" in html

def test_delete_role_blocked_with_users(client):
    # Create role and assign a test user
    cursor = mysql.connection.cursor()
    cursor.execute("INSERT INTO roles (name, is_builtin) VALUES ('TEST_ROLE_BLOCKED', 0)")
    cursor.execute("INSERT INTO user (username, password, type) VALUES ('TEST_USR_BLOCKED', 'dummy', 'TEST_ROLE_BLOCKED')")
    mysql.connection.commit()
    
    cursor.execute("SELECT id FROM roles WHERE name = 'TEST_ROLE_BLOCKED' LIMIT 1")
    role_id = cursor.fetchone()['id']
    cursor.close()

    # Attempt to post delete
    response = client.post(f'/roles/{role_id}/supprimer', follow_redirects=True)
    html = response.data.decode('utf-8')

    # Cleanup
    cursor = mysql.connection.cursor()
    cursor.execute("DELETE FROM user WHERE username = 'TEST_USR_BLOCKED'")
    cursor.execute("DELETE FROM roles WHERE name = 'TEST_ROLE_BLOCKED'")
    mysql.connection.commit()
    cursor.close()

    assert "Ce rôle est attribué à" in html

def test_super_admin_voir_no_delete_button(client):
    cursor = mysql.connection.cursor()
    cursor.execute("SELECT id FROM roles WHERE name = 'SUPER ADMIN' LIMIT 1")
    sa_id = cursor.fetchone()['id']
    cursor.close()

    response = client.get(f'/roles/{sa_id}')
    html = response.data.decode('utf-8')

    # Check that there is no delete button/form targeted to SUPER ADMIN delete
    assert f"/roles/{sa_id}/supprimer" not in html

def test_restricted_role_sidebar_visibility(client):
    # 1. Create a role with only 'interventions' enabled
    cursor = mysql.connection.cursor()
    # Delete first in case it exists from a previous aborted run
    cursor.execute("DELETE FROM roles WHERE name = 'TEST_ROLE_RESTRICTED'")
    mysql.connection.commit()
    
    # Insert role with only interventions=1, and all others=0
    columns = ['name', 'description', 'is_builtin', 'color', 'icon', 'notif_config_default']
    values = ['TEST_ROLE_RESTRICTED', 'Only Interventions', 0, '#e11d48', 'fa-tools', '{}']
    
    # We will build columns for permissions
    permission_cols = [k for k in PERMISSION_KEYS]
    columns += permission_cols
    values += [1 if k == 'interventions' else 0 for k in permission_cols]
    
    placeholders = ", ".join(["%s"] * len(columns))
    cols_str = ", ".join([f"`{c}`" for c in columns])
    sql = f"INSERT INTO roles ({cols_str}) VALUES ({placeholders})"
    cursor.execute(sql, tuple(values))
    mysql.connection.commit()
    cursor.close()
    
    # 2. Modify the client session to use the restricted role
    with client.session_transaction() as sess:
        sess['user_role'] = 'TEST_ROLE_RESTRICTED'
        sess['username'] = 'TEST_USER_RESTRICTED'
        
    try:
        response = client.get('/dashboard')
        html = response.data.decode('utf-8')
        
        # Verify that 'Interventions' is present in the HTML (wrapped in section Maintenance)
        assert "Interventions" in html
        
        # Verify that other modules are NOT present in the sidebar
        assert "Familles" not in html
        assert "Opérations" not in html
        assert "Opérateurs" not in html
        assert "Qualifications" not in html
        assert "Outillages" not in html
        assert "Gammes" not in html
        assert "Constats" not in html
        assert "Rapports de contrôle" not in html
        assert "Utilisateurs" not in html
        assert "Rôles" not in html
        assert "Suivi des actions" not in html
    finally:
        # Cleanup
        cursor = mysql.connection.cursor()
        cursor.execute("DELETE FROM roles WHERE name = 'TEST_ROLE_RESTRICTED'")
        mysql.connection.commit()
        cursor.close()


def test_interventions_visibility_and_filtering_by_role(client):
    cursor = mysql.connection.cursor()
    # 1. Fetch a valid mei id
    cursor.execute("SELECT id FROM mei LIMIT 1")
    mei_row = cursor.fetchone()
    mei_id = mei_row['id'] if mei_row else 1

    # Clean up any residual test interventions first
    cursor.execute("DELETE FROM dr WHERE username IN ('TEST_USER_A', 'TEST_USER_B')")
    mysql.connection.commit()

    # 2. Insert two test interventions
    num_a = 'T_NUM_A'
    num_b = 'T_NUM_B'
    today_str = datetime.now().strftime('%Y-%m-%d')
    cursor.execute("""
        INSERT INTO dr (numero, username, date, id_mei, date_arret, heure, panne, description, 
                       degre, user_mei, resp_user, est_consulter, est_traiter, annuler)
        VALUES (%s, 'TEST_USER_A', %s, %s, %s, '12:00', 'Panne test A', 
                'Description A', 'Normal', 'TEST_USER_A', '', 'non', 'non', 'non')
    """, (num_a, today_str, mei_id, today_str))
    id_a = cursor.lastrowid

    cursor.execute("""
        INSERT INTO dr (numero, username, date, id_mei, date_arret, heure, panne, description, 
                       degre, user_mei, resp_user, est_consulter, est_traiter, annuler)
        VALUES (%s, 'TEST_USER_B', %s, %s, %s, '12:00', 'Panne test B', 
                'Description B', 'Normal', 'TEST_USER_B', '', 'non', 'non', 'non')
    """, (num_b, today_str, mei_id, today_str))
    id_b = cursor.lastrowid
    mysql.connection.commit()
    cursor.close()

    try:
        # 3. Authenticate as TEST_USER_A (PRODUCTION role - can_edit is False)
        with client.session_transaction() as sess:
            sess['user_id'] = 8888
            sess['username'] = 'TEST_USER_A'
            sess['user_role'] = 'PRODUCTION'
            sess['notif_config'] = '{}'

        # 4. GET /interventions as TEST_USER_A
        response = client.get('/interventions')
        html = response.data.decode('utf-8')
        assert num_a in html
        assert num_b not in html

        # 5. GET /dashboard as TEST_USER_A
        response = client.get('/dashboard')
        html = response.data.decode('utf-8')
        assert "Tableau de bord" in html

        # 6. Attempt to view B's intervention details (should be unauthorized)
        response = client.get(f'/interventions/voir/{id_b}', follow_redirects=True)
        html = response.data.decode('utf-8')
        assert "autorisation de voir cette intervention." in html

        # 7. Authenticate as SUPER ADMIN (should see all)
        with client.session_transaction() as sess:
            sess['user_id'] = 9999
            sess['username'] = 'TEST_ADMIN'
            sess['user_role'] = 'SUPER ADMIN'
            sess['notif_config'] = '{}'

        # 8. GET /interventions as SUPER ADMIN (should see both)
        response = client.get('/interventions')
        html = response.data.decode('utf-8')
        assert num_a in html
        assert num_b in html

        # 9. View B's intervention details as SUPER ADMIN (should succeed)
        response = client.get(f'/interventions/voir/{id_b}')
        assert response.status_code == 200
        html = response.data.decode('utf-8')
        assert num_b in html

    finally:
        # Cleanup
        cursor = mysql.connection.cursor()
        cursor.execute("DELETE FROM dr WHERE id IN (%s, %s)", (id_a, id_b))
        mysql.connection.commit()
        cursor.close()
