import * as common from '/pages/src/common.mjs';
import * as o101 from './o101/common.mjs';

const listContainer = document.getElementById('list-container');
const headerRow = document.getElementById('header-row');
const dashEl = document.getElementById('dash');
const wrapperEl = document.getElementById('wrapper');
const checkboxesContainer = document.getElementById('cols-checkboxes');
const settingsPanel = document.getElementById('settings-panel');

// --- DURÉES DES POWER-UPS ZWIFT (en ms) ---
const PU_DURATIONS = {
    "LIGHTNESS": 30000, "DRAFTBOOST": 40000, "AERO": 15000,
    "UNDRAFTABLE": 20000, "CLOAK": 15000, "STEAMROLLER": 30000, "ANVIL": 30000,
    "1": 30000, "2": 40000, "3": 15000, "4": 20000, "5": 15000, "6": 30000, "7": 30000
};

const puTracker = new Map();

// --- DICTIONNAIRE DES MAILLOTS DISTINCTIFS ---
const DISTINCTIVE_JERSEYS = {
    1001: 'images/maillot-vert.png',   
    1002: 'images/maillot-apois.png',  
    1003: 'images/maillot-orange.png'  
};

// --- VARIABLES DU NOUVEAU MOTEUR FTS ---
let activeSprintLeaders = new Map();
let activeKOMLeaders = new Map();
let activeLapLeaders = new Map();
let lastFtsScan = 0;
let cachedSubgroupId = null;
let cachedEventStart = null;

// --- LA BASE DE DONNÉES "ZENMASTER" ---
const knownEventRiders = new Map();

// --- VARIABLES TACTIQUES ---
let watchedRidersFull = []; // Format complet pour l'UI: [{id: 123, name: "Dupont"}]
let watchedTeams = [];      // Format: ["GHOST"]

let currentNearbyRiders = [];
let currentNearbyTeams = new Set();
let lastRiderCount = 0;
let lastTeamCount = 0;

// --- DEFINITION DES COLONNES ---
const ALL_COLS = [
    { id: 'flag',  label: 'NAT',  width: '40px', def: true,  align: 'center' },
    { id: 'cat',   label: 'CAT',  width: '40px', def: true,  align: 'center' },
    { id: 'pu',    label: 'PU',   width: '35px', def: true,  align: 'center' },
    { id: 'grp',   label: 'GRP',  width: '35px', def: true,  align: 'center' },
    { id: 'name',  label: 'NOM',  width: '200px', def: true,  align: 'left' }, 
    { id: 'team',  label: 'CLUB', width: '95px', def: true,  align: 'left' },
    { id: 'draft', label: 'ASP',  width: '50px', def: false, align: 'right' },
    { id: 'watts', label: 'PWR',  width: '60px', def: true,  align: 'right' },
    { id: 'wkg',   label: 'WKG',  width: '55px', def: true,  align: 'right' },
    { id: 'bpm',   label: 'HR',   width: '45px', def: true,  align: 'right' },
    { id: 'gap',   label: 'GAP',  width: '65px', def: true,  align: 'right' }
];

let settings = {
    opacity: 90,
    zoom: 100,
    maxRiders: 30, 
    autoRiders: false, 
    showHeaders: true, 
    showJerseys: true,
    refreshRate: 1,
    cols: {},      
    colWidths: {},
    colFontSizes: {},  
    panelPos: { x: 50, y: 50 } 
};

let calculatedMaxRiders = 30;
let lastUpdate = 0; 

// --- SCANNER DE BASE DE DONNÉES INTERNE ZENMASTER (INDEXEDDB) ---
let zmTeamAssignments = null;
let zmAllTeams = null;

async function fetchZenmasterTeamsDirectly() {
    try {
        if (!indexedDB.databases) return;
        
        const dbs = await indexedDB.databases();
        let dbNamesToScan = dbs.map(db => db.name).filter(name => 
            name.toLowerCase().includes('team') || 
            name.toLowerCase().includes('point') ||
            name.toLowerCase().includes('zen')
        );

        if (dbNamesToScan.length === 0) {
            dbNamesToScan = ['teams', 'points-leaderboard', 'zenTeams'];
        }

        let foundAssignments = null;
        let foundTeams = null;

        for (let dbName of dbNamesToScan) {
            const db = await new Promise((resolve) => {
                const req = indexedDB.open(dbName);
                req.onsuccess = () => resolve(req.result);
                req.onerror = () => resolve(null);
            });

            if (!db) continue;

            for (let storeName of db.objectStoreNames) {
                const data = await new Promise((resolve) => {
                    try {
                        const tx = db.transaction(storeName, 'readonly');
                        const store = tx.objectStore(storeName);
                        const req = store.getAll();
                        req.onsuccess = () => resolve(req.result);
                        req.onerror = () => resolve(null);
                    } catch(e) { resolve(null); }
                });

                if (data && data.length > 0) {
                    const isAssignments = data.some(d => d.zwid !== undefined || d.athleteId !== undefined || (d.id !== undefined && typeof d.id === 'number' && d.id > 1000));
                    if (isAssignments) foundAssignments = data;
                    else if (data.some(d => d.color || d.bgColor || d.hex_color || storeName.toLowerCase().includes('team'))) foundTeams = data;
                }
            }
            db.close();
        }

        if (foundAssignments) zmTeamAssignments = foundAssignments;
        if (foundTeams) zmAllTeams = foundTeams;
        
    } catch(e) {}
}

fetchZenmasterTeamsDirectly();
setInterval(fetchZenmasterTeamsDirectly, 5000);

function getZenmasterOverride(athleteId, rawTeam) {
    let matchedTeamName = null;
    let matchedTeamColor = null;

    if (zmTeamAssignments) {
        let assignment = null;
        if (Array.isArray(zmTeamAssignments)) {
            assignment = zmTeamAssignments.find(t => String(t.zwid) === String(athleteId) || String(t.id) === String(athleteId) || String(t.athleteId) === String(athleteId));
        } else if (typeof zmTeamAssignments === 'object') {
            assignment = zmTeamAssignments[athleteId];
        }
        if (assignment) {
            matchedTeamName = assignment.team || assignment.teamId || assignment.teamName || assignment.name || (typeof assignment === 'string' ? assignment : null);
        }
    }

    let searchTeamName = matchedTeamName || rawTeam;
    if (searchTeamName && zmAllTeams) {
        let teamInfo = null;
        if (Array.isArray(zmAllTeams)) {
            teamInfo = zmAllTeams.find(t => 
                (t.name && String(t.name).toLowerCase() === String(searchTeamName).toLowerCase()) ||
                (t.team && String(t.team).toLowerCase() === String(searchTeamName).toLowerCase()) ||
                (t.id && String(t.id).toLowerCase() === String(searchTeamName).toLowerCase())
            );
        } else if (typeof zmAllTeams === 'object') {
            teamInfo = zmAllTeams[searchTeamName] || Object.values(zmAllTeams).find(t => t.name && String(t.name).toLowerCase() === String(searchTeamName).toLowerCase());
        }

        if (teamInfo) {
            matchedTeamColor = teamInfo.color || teamInfo.bgColor || teamInfo.hex_color || null;
            matchedTeamName = teamInfo.name || teamInfo.team || searchTeamName;
        }
    }

    return {
        name: (matchedTeamName && typeof matchedTeamName === 'string' && matchedTeamName.trim() !== '') ? matchedTeamName : null,
        color: (matchedTeamColor && matchedTeamColor !== '#FFF' && matchedTeamColor !== '#FFFFFF') ? matchedTeamColor : null
    };
}

// --- CACHE API SAUCE (POUR LES CATEGORIES) ---
const subgroupCache = new Map();
const pendingRequests = new Set();

function getSubgroupLabel(id) {
    if (!id) return null;
    if (subgroupCache.has(id)) return subgroupCache.get(id);
    
    if (!pendingRequests.has(id)) {
        pendingRequests.add(id);
        if (common && common.rpc && typeof common.rpc.getEventSubgroup === 'function') {
            common.rpc.getEventSubgroup(id).then(sg => {
                if (sg && sg.subgroupLabel) subgroupCache.set(id, sg.subgroupLabel);
                else if (sg && sg.label) subgroupCache.set(id, sg.label);
                else {
                    subgroupCache.set(id, null);
                    setTimeout(() => subgroupCache.delete(id), 10000);
                }
                pendingRequests.delete(id);
            }).catch(() => pendingRequests.delete(id));
        } else {
            pendingRequests.delete(id);
        }
    }
    return null; 
}

// --- GESTION REGLAGES ET TACTIQUE ---
function loadSettings() {
    const sOp = localStorage.getItem('myMod_Coureur_Op');
    const sZoom = localStorage.getItem('myMod_Coureur_Zoom');
    
    settings.opacity = sOp ? parseInt(sOp) : 90;
    settings.zoom = sZoom ? parseInt(sZoom) : 100;

    const sMax = localStorage.getItem('myMod_Coureur_MaxRiders');
    settings.maxRiders = sMax ? parseInt(sMax) : 30;

    const sAuto = localStorage.getItem('myMod_Coureur_AutoRiders');
    settings.autoRiders = sAuto !== null ? (sAuto === 'true') : false;

    const sHeads = localStorage.getItem('myMod_Coureur_ShowHead');
    settings.showHeaders = sHeads !== null ? (sHeads === 'true') : true;

    const sJerseys = localStorage.getItem('myMod_Coureur_Jerseys');
    if (sJerseys !== null) settings.showJerseys = (sJerseys === 'true');

    const sRef = localStorage.getItem('myMod_Coureur_Refresh');
    if (sRef) settings.refreshRate = parseInt(sRef);

    const sCols = localStorage.getItem('myMod_Coureur_Cols_V6'); 
    if (sCols) {
        settings.cols = JSON.parse(sCols);
        ALL_COLS.forEach(c => {
            if (settings.cols[c.id] === undefined) settings.cols[c.id] = c.def;
        });
    }
    else {
        ALL_COLS.forEach(c => settings.cols[c.id] = c.def);
    }

    const sWidths = localStorage.getItem('myMod_Coureur_Widths');
    if (sWidths) settings.colWidths = JSON.parse(sWidths);

    const sFonts = localStorage.getItem('myMod_Coureur_ColFonts');
    if (sFonts) settings.colFontSizes = JSON.parse(sFonts);
    
    const sPos = localStorage.getItem('myMod_Coureur_PanelPos');
    if(sPos) settings.panelPos = JSON.parse(sPos);

    // --- CHARGEMENT TACTIQUE COMPLET (Noms + IDs) ---
    const sWRF = localStorage.getItem('myMod_WatchedRiders_Names');
    if (sWRF) {
        watchedRidersFull = JSON.parse(sWRF);
    } else {
        const sWR = localStorage.getItem('myMod_WatchedRiders'); // Rétrocompatibilité
        if (sWR) {
            const ids = JSON.parse(sWR);
            watchedRidersFull = ids.map(id => ({id: id, name: "Cible " + id}));
        }
    }

    const sWT = localStorage.getItem('myMod_WatchedTeams');
    if (sWT) watchedTeams = JSON.parse(sWT);

    if (document.getElementById('in-opacity')) document.getElementById('in-opacity').value = settings.opacity;
    if (document.getElementById('in-zoom')) document.getElementById('in-zoom').value = settings.zoom;
    
    if (settingsPanel) {
        settingsPanel.style.left = settings.panelPos.x + 'px';
        settingsPanel.style.top = settings.panelPos.y + 'px';
    }
    
    if (settings.autoRiders) calculateAutoRiders();

    renderSettingsUI();
    initTabsUI();
    renderWatchedListsUI();
    applyVisuals();
    updateGridLayout();
    initDraggablePanel();

    window.addEventListener('resize', () => {
        if (settings.autoRiders) calculateAutoRiders();
    });
}

function calculateAutoRiders() {
    const h = document.documentElement.clientHeight || window.innerHeight;
    const headerHeight = settings.showHeaders ? 40 : 5;
    const marginSafety = 20; 
    const availableHeight = h - headerHeight - marginSafety;
    const rowHeight = 38; 
    const count = Math.floor(availableHeight / rowHeight);
    calculatedMaxRiders = Math.min(Math.max(3, count), 50);
}

function saveSettings() {
    if (document.getElementById('in-opacity')) settings.opacity = parseInt(document.getElementById('in-opacity').value);
    if (document.getElementById('in-zoom')) settings.zoom = parseInt(document.getElementById('in-zoom').value);
    
    const inMax = document.getElementById('in-max-riders');
    if(inMax) settings.maxRiders = parseInt(inMax.value);

    const inRef = document.getElementById('in-refresh');
    if(inRef) settings.refreshRate = parseInt(inRef.value);

    const chkAuto = document.getElementById('chk-auto-riders');
    if(chkAuto) settings.autoRiders = chkAuto.checked;

    const chkHead = document.getElementById('chk-show-headers');
    if(chkHead) settings.showHeaders = chkHead.checked;

    const chkJerseys = document.getElementById('chk-show-jerseys');
    if(chkJerseys) settings.showJerseys = chkJerseys.checked;

    ALL_COLS.forEach(c => {
        const chk = document.getElementById(`chk-${c.id}`);
        if(chk) settings.cols[c.id] = chk.checked;
    });
    
    localStorage.setItem('myMod_Coureur_Op', settings.opacity);
    localStorage.setItem('myMod_Coureur_Zoom', settings.zoom);
    localStorage.setItem('myMod_Coureur_MaxRiders', settings.maxRiders);
    localStorage.setItem('myMod_Coureur_Refresh', settings.refreshRate);
    localStorage.setItem('myMod_Coureur_AutoRiders', settings.autoRiders);
    localStorage.setItem('myMod_Coureur_ShowHead', settings.showHeaders);
    localStorage.setItem('myMod_Coureur_Jerseys', settings.showJerseys);
    localStorage.setItem('myMod_Coureur_Cols_V6', JSON.stringify(settings.cols)); 
    localStorage.setItem('myMod_Coureur_Widths', JSON.stringify(settings.colWidths));
    localStorage.setItem('myMod_Coureur_ColFonts', JSON.stringify(settings.colFontSizes));
    localStorage.setItem('myMod_Coureur_PanelPos', JSON.stringify(settings.panelPos));

    // SAUVEGARDE TACTIQUE (Compatible Mod DS)
    localStorage.setItem('myMod_WatchedRiders_Names', JSON.stringify(watchedRidersFull));
    localStorage.setItem('myMod_WatchedRiders', JSON.stringify(watchedRidersFull.map(r => r.id)));
    localStorage.setItem('myMod_WatchedTeams', JSON.stringify(watchedTeams));

    if (settings.autoRiders) calculateAutoRiders();

    applyVisuals();
    updateGridLayout();
    if (settingsPanel) settingsPanel.style.display = 'none';
}

function initDraggablePanel() {
    const handle = document.getElementById('panel-drag-handle');
    if (!handle || !settingsPanel) return;

    let isDragging = false;
    let startX, startY, initialLeft, initialTop;

    handle.addEventListener('mousedown', (e) => {
        isDragging = true;
        startX = e.clientX;
        startY = e.clientY;
        initialLeft = settingsPanel.offsetLeft;
        initialTop = settingsPanel.offsetTop;
        handle.style.cursor = 'grabbing';
    });

    document.addEventListener('mousemove', (e) => {
        if (!isDragging) return;
        const dx = e.clientX - startX;
        const dy = e.clientY - startY;
        settings.panelPos.x = initialLeft + dx;
        settings.panelPos.y = initialTop + dy;
        settingsPanel.style.left = settings.panelPos.x + 'px';
        settingsPanel.style.top = settings.panelPos.y + 'px';
    });

    document.addEventListener('mouseup', () => {
        if(isDragging) {
            isDragging = false;
            handle.style.cursor = 'grab';
        }
    });
}

function initTabsUI() {
    document.querySelectorAll('.tab-btn').forEach(btn => {
        btn.addEventListener('click', (e) => {
            document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active'));
            document.querySelectorAll('.tab-pane').forEach(p => p.classList.remove('active'));
            e.target.classList.add('active');
            document.getElementById(e.target.getAttribute('data-tab')).classList.add('active');
            
            if (e.target.getAttribute('data-tab') === 'tab-tactics') {
                populateTacticsSelects();
            }
        });
    });

    document.getElementById('btn-add-rider').addEventListener('click', () => {
        const sel = document.getElementById('sel-add-rider');
        const opt = sel.options[sel.selectedIndex];
        if (!opt || !opt.value) return;
        const id = Number(opt.value);
        const name = opt.text;
        
        if (!watchedRidersFull.some(r => r.id === id)) {
            watchedRidersFull.push({id, name});
            saveSettings();
            renderWatchedListsUI();
        }
    });

    document.getElementById('btn-add-team').addEventListener('click', () => {
        const sel = document.getElementById('sel-add-team');
        const teamName = sel.value;
        if (!teamName) return;
        
        if (!watchedTeams.includes(teamName)) {
            watchedTeams.push(teamName);
            saveSettings();
            renderWatchedListsUI();
        }
    });
}

function renderWatchedListsUI() {
    const rList = document.getElementById('watched-riders-list');
    if(rList) {
        rList.innerHTML = watchedRidersFull.map(r => `
            <div class="watched-item">
                <span>${r.name}</span>
                <button class="btn-remove" onclick="window.removeWatchedRider(${r.id})">❌</button>
            </div>
        `).join('');
    }

    const tList = document.getElementById('watched-teams-list');
    if(tList) {
        tList.innerHTML = watchedTeams.map(t => `
            <div class="watched-item">
                <span>${t}</span>
                <button class="btn-remove" onclick="window.removeWatchedTeam('${t}')">❌</button>
            </div>
        `).join('');
    }
}

window.removeWatchedRider = (id) => {
    watchedRidersFull = watchedRidersFull.filter(r => r.id !== id);
    saveSettings();
    renderWatchedListsUI();
};

window.removeWatchedTeam = (teamName) => {
    watchedTeams = watchedTeams.filter(t => t !== teamName);
    saveSettings();
    renderWatchedListsUI();
};

function populateTacticsSelects() {
    const selRider = document.getElementById('sel-add-rider');
    const selTeam = document.getElementById('sel-add-team');
    if(!selRider || !selTeam) return;

    // Sécurité: ne pas rafraîchir le menu si l'utilisateur est en train de cliquer dedans
    if (document.activeElement === selRider || document.activeElement === selTeam) return;

    // Déduplication
    const uniqueRiders = Array.from(new Map(currentNearbyRiders.map(item => [item.id, item])).values());

    if (uniqueRiders.length !== lastRiderCount) {
        const currentRiderVal = selRider.value;
        let rHtml = '<option value="">-- Coureurs à proximité --</option>';
        uniqueRiders.sort((a,b) => a.name.localeCompare(b.name)).forEach(r => {
            rHtml += `<option value="${r.id}">${r.name}</option>`;
        });
        selRider.innerHTML = rHtml;
        if(currentRiderVal) selRider.value = currentRiderVal;
        lastRiderCount = uniqueRiders.length;
    }

    if (currentNearbyTeams.size !== lastTeamCount) {
        const currentTeamVal = selTeam.value;
        let tHtml = '<option value="">-- Équipes à proximité --</option>';
        Array.from(currentNearbyTeams).sort().forEach(t => {
            tHtml += `<option value="${t}">${t}</option>`;
        });
        selTeam.innerHTML = tHtml;
        if(currentTeamVal) selTeam.value = currentTeamVal;
        lastTeamCount = currentNearbyTeams.size;
    }
}

function renderSettingsUI() {
    if (!checkboxesContainer) return;
    checkboxesContainer.innerHTML = '';
    
    const divHead = document.createElement('div');
    divHead.className = 'global-setting';
    divHead.innerHTML = `
        <div style="margin-bottom:5px;">
            <input type="checkbox" id="chk-show-headers" ${settings.showHeaders ? 'checked' : ''}>
            <label for="chk-show-headers" style="font-weight:bold; color:#fc6719;">AFFICHER LES ENTÊTES</label>
        </div>
        <div style="margin-bottom:5px;">
            <input type="checkbox" id="chk-show-jerseys" ${settings.showJerseys ? 'checked' : ''}>
            <label for="chk-show-jerseys" style="font-weight:bold; color:#fc6719;">AFFICHER MAILLOTS (FTS)</label>
        </div>
    `;
    checkboxesContainer.appendChild(divHead);
    
    divHead.querySelector('#chk-show-headers').addEventListener('change', (e) => {
        settings.showHeaders = e.target.checked;
        updateGridLayout();
    });

    divHead.querySelector('#chk-show-jerseys').addEventListener('change', (e) => {
        settings.showJerseys = e.target.checked;
    });

    const divMax = document.createElement('div');
    divMax.className = 'input-group';
    const sliderDisplay = settings.autoRiders ? 'none' : 'block';
    
    divMax.innerHTML = `
        <div style="display:flex; justify-content:space-between; align-items:center;">
            <label>Nombre de coureurs : <span id="max-riders-label" style="color:white; font-weight:bold;">${settings.autoRiders ? 'AUTO' : settings.maxRiders}</span></label>
            <div style="display:flex; align-items:center;">
                <input type="checkbox" id="chk-auto-riders" ${settings.autoRiders ? 'checked' : ''}>
                <label for="chk-auto-riders" style="margin-left:5px; font-size:10px; cursor:pointer;">AUTO</label>
            </div>
        </div>
        <input type="range" id="in-max-riders" min="3" max="60" value="${settings.maxRiders}" style="display:${sliderDisplay}">
    `;
    checkboxesContainer.appendChild(divMax);

    const divRefresh = document.createElement('div');
    divRefresh.className = 'input-group';
    divRefresh.innerHTML = `
        <div style="display:flex; justify-content:space-between; align-items:center;">
            <label>Rafraîchissement : <span id="refresh-label" style="color:white; font-weight:bold;">${settings.refreshRate}s</span></label>
        </div>
        <input type="range" id="in-refresh" min="1" max="10" value="${settings.refreshRate}">
    `;
    checkboxesContainer.appendChild(divRefresh);

    const rangeInput = divMax.querySelector('#in-max-riders');
    const labelSpan = divMax.querySelector('#max-riders-label');
    const autoCheck = divMax.querySelector('#chk-auto-riders');
    const refreshInput = divRefresh.querySelector('#in-refresh');
    const refreshLabel = divRefresh.querySelector('#refresh-label');

    rangeInput.addEventListener('input', (e) => {
        settings.maxRiders = parseInt(e.target.value);
        labelSpan.innerText = settings.maxRiders;
    });

    refreshInput.addEventListener('input', (e) => {
        settings.refreshRate = parseInt(e.target.value);
        refreshLabel.innerText = settings.refreshRate + 's';
    });

    autoCheck.addEventListener('change', (e) => {
        settings.autoRiders = e.target.checked;
        if (settings.autoRiders) {
            rangeInput.style.display = 'none';
            labelSpan.innerText = 'AUTO';
            calculateAutoRiders();
        } else {
            rangeInput.style.display = 'block';
            labelSpan.innerText = settings.maxRiders;
        }
    });

    ALL_COLS.forEach(c => {
        const lbl = c.label || 'NAT'; 
        const checked = settings.cols[c.id] ? 'checked' : '';
        const isFlexible = c.width.includes('fr'); 
        
        let currentW = settings.colWidths[c.id];
        if (!currentW) currentW = parseInt(c.width) || 40; 
        let currentF = settings.colFontSizes[c.id] || 15; 

        let minW = 20, maxW = 150;
        if (c.id === 'name') { minW = 50; maxW = 400; }
        if (c.id === 'team') { minW = 30; maxW = 250; }
        if (c.id === 'grp')  { minW = 20; maxW = 80; } 

        let widthSliderHtml = isFlexible 
            ? `<span class="locked-val">AUTO</span>`
            : `<input type="range" class="mini-slider" id="sli-w-${c.id}" min="${minW}" max="${maxW}" value="${currentW}" title="Larg.: ${currentW}px">`;

        const div = document.createElement('div');
        div.className = 'col-config-block';
        div.innerHTML = `
            <div class="col-head">
                <input type="checkbox" id="chk-${c.id}" ${checked}>
                <label for="chk-${c.id}">${lbl}</label>
            </div>
            <div class="col-params">
                <div class="param-row">
                    <span class="p-lbl">Larg.</span>
                    ${widthSliderHtml}
                </div>
                <div class="param-row">
                    <span class="p-lbl">Txt</span>
                    <input type="range" class="mini-slider" id="sli-f-${c.id}" min="10" max="25" value="${currentF}" title="Taille : ${currentF}px">
                </div>
            </div>
        `;
        checkboxesContainer.appendChild(div);

        if (!isFlexible) {
            div.querySelector(`#sli-w-${c.id}`).addEventListener('input', (e) => {
                settings.colWidths[c.id] = parseInt(e.target.value);
                updateGridLayout(); 
            });
        }
        div.querySelector(`#sli-f-${c.id}`).addEventListener('input', (e) => {
            settings.colFontSizes[c.id] = parseInt(e.target.value);
        });
        div.querySelector(`#chk-${c.id}`).addEventListener('change', (e) => {
             settings.cols[c.id] = e.target.checked;
             updateGridLayout();
        });
    });
}

function updateGridLayout() {
    if (headerRow) headerRow.style.display = settings.showHeaders ? 'grid' : 'none';
    const activeCols = ALL_COLS.filter(c => settings.cols[c.id]);
    let gridTemplateParts = [];
    let totalFixedWidth = 0;

    activeCols.forEach(c => {
        if (c.width.includes('fr')) {
            gridTemplateParts.push('1fr');
            totalFixedWidth += 200; 
        } else {
            const w = settings.colWidths[c.id] || parseInt(c.width);
            gridTemplateParts.push(`${w}px`);
            totalFixedWidth += w;
        }
    });

    const totalW = totalFixedWidth + 10; 
    if (dashEl) {
        dashEl.style.width = `${Math.max(300, totalW)}px`;
        const gridTemplate = gridTemplateParts.join(' ');
        dashEl.style.setProperty('--grid-layout', gridTemplate);
    }

    let headerHtml = '';
    activeCols.forEach(c => {
        headerHtml += `<div class="h-col ${c.align}">${c.label}</div>`;
    });
    if (headerRow) headerRow.innerHTML = headerHtml;
}

function applyVisuals() {
    const opLabel = document.getElementById('op-label');
    if (opLabel) opLabel.innerText = settings.opacity;
    
    if (dashEl) dashEl.style.backgroundColor = `rgba(0, 0, 0, ${settings.opacity/100})`;
    if (listContainer) listContainer.style.backgroundColor = `rgba(0, 0, 0, ${settings.opacity/100})`;
    
    const zoomLabel = document.getElementById('zoom-label');
    if (zoomLabel) zoomLabel.innerText = (settings.zoom/100).toFixed(1);
    
    if (wrapperEl) wrapperEl.style.transform = `scale(${settings.zoom/100})`;
}

// --- UTILITAIRES ---
function formatTime(sec) {
    if (sec == null || isNaN(sec)) return '';
    const abs = Math.abs(sec);
    if (abs < 60) return Math.round(abs) + 's';
    const m = Math.floor(abs / 60);
    const s = Math.floor(abs % 60);
    return `${m}:${s.toString().padStart(2,'0')}`;
}

function getFlagImg(countryCode) {
    if (!countryCode) return '';
    const cc = countryCode.toLowerCase();
    return `<img src="https://flagcdn.com/20x15/${cc}.png" alt="${cc}" onerror="this.style.display='none'">`;
}

function formatName(first, last) {
    if (o101 && o101.fmtFirstName && o101.fmtLastName) {
        try {
            return o101.fmtFirstName({athlete:{firstName:first}}, 1) + '. ' + o101.fmtLastName({athlete:{lastName:last}});
        } catch(e) {}
    }
    if (!last) return first || 'Inconnu';
    let cleanLast = last.replace(/\[.*?\]|\(.*?\)/g, '').trim();
    const fInitial = first ? first.charAt(0).toUpperCase() + '.' : '';
    return `${fInitial} ${cleanLast.toUpperCase()}`;
}

function stringToColorHSL(str) {
    let hash = 0;
    let safeStr = String(str || "");
    for (let i = 0; i < safeStr.length; i++) {
        hash = safeStr.charCodeAt(i) + ((hash << 5) - hash);
    }
    const h = Math.abs(hash) % 360;
    const s = 80;
    const l = 70;
    return `hsl(${h}, ${s}%, ${l}%)`;
}

function sanitizeTeamName(rawTeam) {
    if (!rawTeam) return "Indépendant";
    if (Array.isArray(rawTeam)) rawTeam = rawTeam[0];
    if (typeof rawTeam === 'object' && rawTeam !== null) {
        rawTeam = rawTeam.name || rawTeam.teamName || String(rawTeam);
    }
    const str = String(rawTeam).trim();
    return str === '' ? "Indépendant" : str;
}

function detectCategory(r) {
    let a = r.athlete || {};
    let s = r.state || {};
    let zp = a.zwiftpower || a.zp || {};

    let subId = a.eventSubgroupId || a.subgroupId || r.eventSubgroupId || r.subgroupId || s.eventSubgroupId || s.subgroupId;

    const toLetter = (val) => {
        if (val === undefined || val === null) return null;
        let str = String(val).toUpperCase().trim();
        if (str === '1' || str === 'A' || str.includes('CAT A') || str.includes('GROUP A')) return 'A';
        if (str === '2' || str === 'B' || str.includes('CAT B') || str.includes('GROUP B')) return 'B';
        if (str === '3' || str === 'C' || str.includes('CAT C') || str.includes('GROUP C')) return 'C';
        if (str === '4' || str === 'D' || str.includes('CAT D') || str.includes('GROUP D')) return 'D';
        if (str === '5' || str === 'E' || str.includes('CAT E') || str.includes('GROUP E')) return 'E';
        
        let match = str.match(/\b([A-E])\b/);
        if (match) return match[1];
        return null;
    };

    let cat = null;

    if (!cat) cat = toLetter(zp.category || zp.cat || a.zpCategory || a.zwiftPowerCategory);

    if (!cat && subId) {
        let fetchedLabel = getSubgroupLabel(subId);
        if (fetchedLabel) cat = toLetter(fetchedLabel);
    }

    if (!cat) {
        let fullName = `${a.firstName || ''} ${a.lastName || ''}`.toUpperCase();
        let matchName = fullName.match(/\(\s*([A-E])\s*\)|\[\s*([A-E])\s*\]/);
        if (matchName) cat = matchName[1] || matchName[2];
    }

    if (!cat) {
        let team = a.team || '';
        if (Array.isArray(team)) team = team[0];
        if (team) {
            let matchTeam = String(team).toUpperCase().match(/\(\s*([A-E])\s*\)|\[\s*([A-E])\s*\]/);
            if (matchTeam) cat = matchTeam[1] || matchTeam[2];
        }
    }

    if (!cat) {
        let rawCat = a.category || r.category || r.categoryId || s.categoryId || a.subgroupLabel || r.subgroupLabel;
        if (rawCat === undefined && a.subgroup && typeof a.subgroup === 'object') {
            rawCat = a.subgroup.subgroupLabel || a.subgroup.label;
        } else if (rawCat === undefined && typeof r.subgroup === 'object') {
            rawCat = r.subgroup.subgroupLabel || r.subgroup.label;
        } else if (rawCat === undefined) {
            rawCat = r.subgroup; 
        }
        cat = toLetter(rawCat);
    }

    return cat || '-';
}

function getCategoryBadge(cat) {
    if (!cat || cat === '-' || cat === '') return '-';
    
    let bg = '#555';
    let color = '#fff';
    
    if (cat === 'A') { bg = '#ff3333'; color = '#fff'; }
    else if (cat === 'B') { bg = '#55ff55'; color = '#000'; }
    else if (cat === 'C') { bg = '#33ccff'; color = '#000'; }
    else if (cat === 'D') { bg = '#ffcc33'; color = '#000'; }
    else if (cat === 'E') { bg = '#d633ff'; color = '#fff'; }
    else { return '-'; } 
    
    return `<span style="background-color:${bg}; color:${color}; padding: 2px 6px; border-radius: 4px; font-weight: 900; box-shadow: 0 1px 2px rgba(0,0,0,0.5);">${cat}</span>`;
}

// --- LOGIQUE ZWIFT ---
function updateRiders(data) {
    try {
        const now = Date.now();
        if (now - lastUpdate < settings.refreshRate * 1000) return;
        lastUpdate = now;

        let riders = [];
        if (Array.isArray(data)) riders = data;
        else if (data && data.riders) riders = data.riders;
        else if (data && data.nearby) riders = data.nearby;
        else return;

        if (riders.length === 0) {
            if (listContainer) listContainer.innerHTML = '<div class="status-msg">Aucun coureur proche</div>';
            return;
        }

        if (settings.autoRiders) calculateAutoRiders();

        let myTeamName = null;
        const me = riders.find(r => r.watching);
        if (me && me.athlete) {
            let tName = sanitizeTeamName(me.athlete.team);

            let zmOverride = getZenmasterOverride(me.athlete.id || me.id, tName);
            if (zmOverride.name) {
                tName = String(zmOverride.name).trim();
            } 
            else if (o101 && o101.preferredTeamColor) {
                try {
                    let tc = o101.preferredTeamColor(me.athlete.team, me.athlete.id || me.id);
                    if (tc && tc.name && String(tc.name).trim() !== '') tName = String(tc.name).trim();
                } catch(e) {}
            }
            
            myTeamName = tName;
        }

        const limit = settings.autoRiders ? calculatedMaxRiders : settings.maxRiders;
        let closestRiders = [...riders].sort((a, b) => Math.abs(a.gap || 0) - Math.abs(b.gap || 0)).slice(0, limit);
        let visibleIds = new Set(closestRiders.map(r => r.id || (r.athlete && r.athlete.id)));

        // --- ALIMENTATION LÉGÈRE DES MENUS DÉROULANTS TACTIQUES ---
        currentNearbyRiders = [];
        currentNearbyTeams.clear();
        closestRiders.forEach(r => {
            if (r.athlete) {
                let name = formatName(r.athlete.firstName, r.athlete.lastName);
                let id = r.athlete.id || r.id;
                currentNearbyRiders.push({id, name});

                let tName = sanitizeTeamName(r.athlete.team);
                let zmOverride = getZenmasterOverride(id, tName);
                if (zmOverride.name) tName = String(zmOverride.name).trim();
                
                if (tName !== "Indépendant" && tName !== "") {
                    currentNearbyTeams.add(tName);
                }
            }
        });
        
        // Met à jour les menus déroulants UNIQUEMENT si le panneau tactique est ouvert
        if (settingsPanel && settingsPanel.style.display === 'block') {
            populateTacticsSelects();
        }

        riders.sort((a, b) => (a.gap || 0) - (b.gap || 0));

        let groups = [];
        if (riders.length > 0) {
            let currentGroup = [riders[0]];
            for (let i = 1; i < riders.length; i++) {
                const r = riders[i];
                const prev = riders[i-1];
                const diff = (r.gap || 0) - (prev.gap || 0);

                if (diff > 2) { 
                    groups.push(currentGroup);
                    currentGroup = [r];
                } else {
                    currentGroup.push(r);
                }
            }
            groups.push(currentGroup);
        }

        let html = '';
        const activeCols = ALL_COLS.filter(c => settings.cols[c.id]);
        let groupAlt = false; 

        groups.forEach((group, groupIndex) => {
            const visibleRidersInGroup = group.filter(r => visibleIds.has(r.id || (r.athlete && r.athlete.id)));
            if (visibleRidersInGroup.length === 0) return;

            let avgWkg = 0;
            let groupTeams = new Map();
            let colorsMap = new Map();

            if (group.length > 0) {
                let totalWkg = 0;
                group.forEach(r => {
                    const p = (r.state && r.state.power) || 0;
                    const w = (r.athlete && r.athlete.weight) || 75;
                    totalWkg += (p/w);

                    if (r.athlete) {
                        let athleteId = r.athlete.id || r.id;
                        let tName = sanitizeTeamName(r.athlete.team);
                        let tColor = null;

                        let zmOverride = getZenmasterOverride(athleteId, tName);
                        if (zmOverride.name) tName = String(zmOverride.name).trim();
                        if (zmOverride.color) tColor = zmOverride.color;

                        if (!zmOverride.name && !zmOverride.color && o101 && o101.preferredTeamColor) {
                            try {
                                const tc = o101.preferredTeamColor(r.athlete.team, athleteId);
                                if (tc) {
                                    if (tc.name && String(tc.name).trim() !== '') tName = String(tc.name).trim();
                                    if (tc.color && tc.color !== '#FFF' && tc.color !== '#FFFFFF') tColor = tc.color;
                                }
                            } catch(e) {}
                        }

                        if (tName !== "Indépendant" && tName !== "") {
                            groupTeams.set(tName, (groupTeams.get(tName) || 0) + 1);
                            if (tColor) colorsMap.set(tName, tColor);
                        }
                    }
                });
                avgWkg = (totalWkg / group.length).toFixed(1);
            }

            let teamBadgesHtml = '';
            const sortedGroupTeams = [...groupTeams.entries()].sort((a, b) => b[1] - a[1]);
            
            sortedGroupTeams.slice(0, 10).forEach(([name, count]) => {
                const color = colorsMap.get(name) || stringToColorHSL(name);
                teamBadgesHtml += `<span style="border:1px solid ${color}; color:${color}; background:${color}22; padding:0 3px; border-radius:3px; margin-left:4px; font-size:10px; font-weight:bold;" title="${name}">${count}</span>`;
            });

            let labelGap = '';
            let classGap = 'gap-count';

            if (groupIndex === 0) {
                labelGap = '<span style="color:#44ff44; font-weight:900;">TÊTE</span>';
            } else {
                const prevGroup = groups[groupIndex - 1];
                const lastOfPrev = prevGroup[prevGroup.length - 1];
                const firstOfCurr = group[0];
                const diff = (firstOfCurr.gap || 0) - (lastOfPrev.gap || 0);
                
                groupAlt = !groupAlt;
                labelGap = `<span class="gap-time">+ ${formatTime(diff)}</span>`;
            }

            html += `<div class="gap-separator">
                        ${labelGap}
                        <span class="${classGap}">${group.length} 👤</span>
                        <span class="gap-wkg" style="background:#333; color:#aaa; font-family:monospace; padding:1px 6px; border-radius:10px; font-size:11px;">${avgWkg} w/kg</span>
                        ${teamBadgesHtml}
                     </div>`;

            visibleRidersInGroup.forEach(r => {
                let d = {}; 
                d.flag = ''; d.team = '-';
                d.grp = group.length;

                d.cat = getCategoryBadge(detectCategory(r));

                let isMyTeammate = false;
                let teamColor = '#FFFFFF'; 
                let rawTNameForSelect = "Indépendant";

                if (r.athlete) {
                    d.name = formatName(r.athlete.firstName, r.athlete.lastName);
                    
                    let flagContent = null;
                    if (o101 && o101.fmtFlag) {
                        try { flagContent = o101.fmtFlag({ athlete: r.athlete }); } catch(e) {}
                    }
                    
                    if (flagContent) {
                        d.flag = flagContent;
                    } else {
                        let cc = r.athlete.countryAlpha2 || r.athlete.countryCode;
                        d.flag = getFlagImg(cc); 
                    }

                    let athleteId = r.athlete.id || r.id;
                    let tName = sanitizeTeamName(r.athlete.team);
                    let tColor = null;

                    let zmOverride = getZenmasterOverride(athleteId, tName);
                    if (zmOverride.name) tName = String(zmOverride.name).trim();
                    if (zmOverride.color) tColor = zmOverride.color;
                    
                    if (!zmOverride.name && !zmOverride.color && o101 && o101.preferredTeamColor) {
                        try {
                            const tc = o101.preferredTeamColor(r.athlete.team, athleteId);
                            if (tc) {
                                if (tc.name && String(tc.name).trim() !== '') tName = String(tc.name).trim();
                                if (tc.color && tc.color !== '#FFF' && tc.color !== '#FFFFFF') tColor = tc.color;
                            }
                        } catch(e) {}
                    }

                    d.team = tName;
                    rawTNameForSelect = tName;
                    teamColor = tColor || stringToColorHSL(tName);
                    
                    if (myTeamName && tName !== "Indépendant" && tName === myTeamName && !r.watching) {
                        isMyTeammate = true;
                    }
                } else { d.name = 'Inconnu'; }
        
                const pwr = (r.state && r.state.power) || 0;
                const wgt = (r.athlete && r.athlete.weight) || 75;
                const wkg = (pwr / wgt);
                
                d.watts = pwr > 0 ? Math.round(pwr) : '';
                d.wkg = wkg > 0 ? wkg.toFixed(1) : '';
                d.bpm = (r.state && r.state.heartrate) > 0 ? r.state.heartrate : '';
        
                const draft = (r.state && r.state.draft) || 0;
                d.draft = draft > 5 ? Math.round(draft) : ''; 
        
                const gap = r.gap || 0;
                if (gap === 0) {
                    d.gap = '';
                } else {
                    const timeStr = formatTime(gap);
                    const sign = gap > 0 ? '+' : ''; 
                    const gapColor = gap > 0 ? '#ff5555' : '#55ff55';
                    d.gap = `${sign}<span style="color:${gapColor}">${timeStr}</span>`;
                }

                // --- GESTION PU ET COOLDOWN ---
                let stateToUse = r.state || {};
                if (r.watching && common.athlete && common.athlete.state) {
                    stateToUse = common.athlete.state;
                }

                let puCode = stateToUse.activePowerUp || "";
                if (!puCode && stateToUse.powerup !== undefined) puCode = stateToUse.powerup;
                if (!puCode && stateToUse.powerUp !== undefined) puCode = stateToUse.powerUp;

                let puKey = puCode;
                if (typeof puCode === 'string') {
                    const low = puCode.toLowerCase();
                    if (low.includes('feather')) puKey = 1;
                    else if (low.includes('draft') || low.includes('van')) puKey = 2;
                    else if (low.includes('aero') || low.includes('helmet')) puKey = 3;
                    else if (low.includes('burrito')) puKey = 4;
                    else if (low.includes('cloak') || low.includes('ghost')) puKey = 5;
                    else if (low.includes('steam')) puKey = 6;
                    else if (low.includes('anvil')) puKey = 7;
                }

                let puIcon = '';
                let puStr = String(puKey).toUpperCase();
                let bgStyle = "";

                if (puKey && puKey !== "0" && puKey !== "") {
                    const athId = r.athleteId || r.id;
                    if (!puTracker.has(athId) || puTracker.get(athId).lastType !== puStr) {
                        puTracker.set(athId, { 
                            startTime: now, 
                            duration: PU_DURATIONS[puStr] || 15000, 
                            lastType: puStr 
                        });
                    }
                    const tracker = puTracker.get(athId);
                    const elapsed = now - tracker.startTime;
                    const remainingPct = Math.max(0, 100 - (elapsed / tracker.duration * 100));

                    if (remainingPct > 0) {
                        bgStyle = `background: linear-gradient(to right, rgba(252, 103, 25, 0.4) ${remainingPct}%, transparent ${remainingPct}%);`;
                    } else {
                        puTracker.delete(athId);
                    }
                } else {
                    puTracker.delete(r.athleteId || r.id);
                }

                const imgStyle = 'height: 18px; vertical-align: middle; margin-top: -2px; border-radius: 2px;';

                if (puKey == 1) puIcon = `<img src="images/pu-feather.png" style="${imgStyle}" alt="Feather">`;
                else if (puKey == 2) puIcon = `<img src="images/pu-draft.png" style="${imgStyle}" alt="Van">`;
                else if (puKey == 3) puIcon = `<img src="images/pu-aero.png" style="${imgStyle}" alt="Aero">`;
                else if (puKey == 4) puIcon = `<img src="images/pu-burrito.png" style="${imgStyle}" alt="Burrito">`;
                else if (puKey == 5) puIcon = `<img src="images/pu-ghost.png" style="${imgStyle}" alt="Ghost">`;
                else if (puKey == 6) puIcon = `<img src="images/pu-steamroller.png" style="${imgStyle}" alt="Steamroller">`;
                else if (puKey == 7) puIcon = `<img src="images/pu-anvil.png" style="${imgStyle}" alt="Anvil">`;
                else if (puKey == 8) puIcon = `<img src="images/pu-coffee.png" style="${imgStyle}" alt="Coffee">`;

                // --- LOGIQUE MAILLOTS DISTINCTIFS ---
                if (puIcon === '' && settings.showJerseys) {
                    const athIdStr = String(r.athleteId || r.id || (r.athlete && r.athlete.id));
                    let jId = (r.state && r.state.jerseyId) || (r.athlete && r.athlete.jerseyId) || (r.athlete && r.athlete.jersey) || 0;
                    
                    let komCount = activeKOMLeaders.get(athIdStr) || 0;
                    let sprintCount = activeSprintLeaders.get(athIdStr) || 0;
                    let lapCount = activeLapLeaders.get(athIdStr) || 0;

                    if (komCount > 0 && sprintCount > 0) {
                        puIcon = `<img src="images/maillot-vert-apois.png" style="${imgStyle}" alt="Vert+Pois">`;
                    }
                    else if (komCount > 0) {
                        let imgName = komCount > 1 ? `maillot-apois-${Math.min(komCount, 4)}.png` : `maillot-apois.png`;
                        puIcon = `<img src="images/${imgName}" style="${imgStyle}" alt="Maillot Pois">`;
                    }
                    else if (sprintCount > 0) {
                        let imgName = sprintCount > 1 ? `maillot-vert-${Math.min(sprintCount, 4)}.png` : `maillot-vert.png`;
                        puIcon = `<img src="images/${imgName}" style="${imgStyle}" alt="Maillot Vert">`;
                    }
                    else if (lapCount > 0) {
                        let imgName = lapCount > 1 ? `maillot-orange-${Math.min(lapCount, 2)}.png` : `maillot-orange.png`;
                        puIcon = `<img src="images/${imgName}" style="${imgStyle}" alt="Maillot Orange">`;
                    }
                    else if (jId !== 0 && jId !== '') {
                        if (DISTINCTIVE_JERSEYS[jId]) {
                            puIcon = `<img src="${DISTINCTIVE_JERSEYS[jId]}" style="${imgStyle}" alt="Maillot">`;
                        }
                        else if (typeof jId === 'string' && jId.toLowerCase().includes('green')) {
                            puIcon = `<img src="images/maillot-vert.png" style="${imgStyle}" alt="Maillot Vert">`;
                        }
                        else if (typeof jId === 'string' && (jId.toLowerCase().includes('polka') || jId.toLowerCase().includes('kom'))) {
                            puIcon = `<img src="images/maillot-apois.png" style="${imgStyle}" alt="Maillot Pois">`;
                        }
                    }
                }
                
                d.pu = puIcon;
        
                let z = 'z1';
                if (wkg >= 6.0) z='z6'; else if (wkg >= 4.5) z='z5'; else if (wkg >= 3.7) z='z4';
                else if (wkg >= 3.2) z='z3'; else if (wkg >= 2.5) z='z2';
        
                let rowClass = 'rider-row';
                if (r.watching) rowClass += ' watching'; 
                else if (isMyTeammate) rowClass += ' teammate';
                else if (groupAlt) rowClass += ' group-alt'; 
                
                const clickId = r.athleteId || r.id || (r.athlete && r.athlete.id);
                
                html += `<div class="${rowClass}" data-id="${clickId}" title="Cliquer pour observer ce coureur">`;
                
                activeCols.forEach(col => {
                    let content = d[col.id];
                    let classes = `cell ${col.align}`;
                    let titleText = String(content).replace(/<[^>]*>?/gm, '');
                    const fontSize = settings.colFontSizes[col.id] || 15;
                    let style = `font-size:${fontSize}px;`;
                    
                    if (col.id === 'flag') classes += ' r-flag'; 
                    if (col.id === 'cat') classes += ' r-cat';   
                    if (col.id === 'grp') classes += ' r-grp'; 
                    if (col.id === 'pu') classes += ' r-pu'; 
                    
                    // --- MOTEUR TACTIQUE : CADRE ROUGE (MEMOIRE PERMANENTE) ---
                    if (col.id === 'name') {
                        classes += ' r-name';
                        if (watchedRidersFull.some(wr => wr.id === clickId)) classes += ' watched-target';
                        style += bgStyle; 
                    }
                    
                    if (col.id === 'team') {
                        classes += ' r-team';
                        titleText = rawTNameForSelect;
                        if (watchedTeams.includes(rawTNameForSelect)) classes += ' watched-target';

                        if (content !== '-') {
                            style += `
                                border: 1px solid ${teamColor}; 
                                color: ${teamColor};
                                background: ${teamColor}15;
                                border-radius: 4px;
                                padding: 0 4px;
                                font-weight: 600;
                            `;
                        }
                    }

                    if (col.id === 'draft') classes += ' r-draft'; 
                    if (col.id === 'watts') classes += ' r-watts';
                    if (col.id === 'bpm') classes += ' r-bpm';
                    if (col.id === 'wkg') classes += ' r-wkg ' + z;
                    if (col.id === 'gap') classes += ' r-gap';
        
                    html += `<div class="${classes}" style="${style}" title="${titleText}">${content}</div>`;
                });
                html += `</div>`;
            });
        });

        if (listContainer) listContainer.innerHTML = html;
    } catch (err) {
        console.error(err);
    }
}

export async function main() {
    if (o101 && o101.initNationFlags) {
        try { await o101.initNationFlags(); } catch (e) { console.warn("Erreur Init O101 Flags:", e); }
    }
    if (o101 && o101.initTeamColors) {
        try { await o101.initTeamColors(); } catch (e) { console.warn("Erreur Init O101 TeamColors:", e); }
    }

    if (listContainer) listContainer.innerHTML = '<div class="status-msg" style="color:orange">Démarrage...</div>';

    loadSettings();
    
    document.getElementById('btn-settings').addEventListener('click', () => {
        const p = document.getElementById('settings-panel');
        if (p) {
            if (p.style.display === 'block') {
                p.style.display = 'none';
            } else {
                p.style.display = 'block';
                populateTacticsSelects();
            }
        }
    });
    
    document.getElementById('btn-save').addEventListener('click', saveSettings);
    
    document.getElementById('in-opacity').addEventListener('input', (e) => {
        settings.opacity = e.target.value; applyVisuals();
    });
    document.getElementById('in-zoom').addEventListener('input', (e) => {
        settings.zoom = e.target.value; applyVisuals();
    });

    // --- ECOUTEUR DE CLIC (VUE FAN) ---
    if (listContainer) {
        listContainer.addEventListener('click', async (e) => {
            const row = e.target.closest('.rider-row');
            if (row && row.dataset.id) {
                const targetId = Number(row.dataset.id);
                try {
                    if (common.rpc && typeof common.rpc.watch === 'function') {
                        await common.rpc.watch(targetId);
                    }
                } catch (err) {
                    console.warn("Impossible de changer la caméra vers ce coureur :", err);
                }
            }
        });
    }

    // ALIMENTATION DE LA MÉMOIRE SÉCURISÉE EN TÂCHE DE FOND
    if (common && common.subscribe) {
        common.subscribe('athletes', (athletes) => {
            if (!athletes) return;
            for (const ath of athletes) {
                if (ath && ath.state) {
                    let subId = ath.state.eventSubgroupId;
                    if (subId === undefined) subId = ath.state.subgroupId;
                    if (subId === undefined) subId = 0; 
                    knownEventRiders.set(Number(ath.id), Number(subId));
                }
            }
        });

        common.subscribe('states', (states) => {
            if (!states) return;
            for (const s of states) {
                let subId = s.eventSubgroupId;
                if (subId === undefined) subId = s.subgroupId;
                if (subId !== undefined) {
                    knownEventRiders.set(Number(s.id), Number(subId));
                }
            }
        });
    }

    if (common && common.initInteractionListeners) {
        common.initInteractionListeners();
        
        if (typeof common.onSauceConnected === 'function') {
            common.onSauceConnected((isConnected) => {
                if (listContainer) {
                    if (isConnected) {
                        listContainer.innerHTML = '<div class="status-msg" style="color:yellow">Sauce Connecté... Attente Zwift</div>';
                    } else {
                        listContainer.innerHTML = '<div class="status-msg" style="color:red">Sauce Déconnecté</div>';
                    }
                }
            });
        }

        // --- MOTEUR FTS EN ARRIÈRE-PLAN ---
        common.subscribe('athlete/watching', async (packet) => {
            if (!packet) return;

            const now = Date.now();
            if (now - lastFtsScan < 5000) return; 
            lastFtsScan = now;

            const subId = common.athlete?.state?.eventSubgroupId || packet?.state?.eventSubgroupId;
            if (subId && subId !== cachedSubgroupId) {
                cachedSubgroupId = subId;
                cachedEventStart = null; 
                try {
                    const sg = await common.rpc.getEventSubgroup(subId);
                    if (sg && (sg.eventSubgroupStart || sg.startDate)) {
                        cachedEventStart = new Date(sg.eventSubgroupStart || sg.startDate).getTime();
                    }
                } catch(e) {}
            }

            const dataSource = packet.segmentData || (common.athlete ? common.athlete.segmentData : null);
            if (!dataSource) return;

            let entries = [];
            if (typeof dataSource.values === 'function') entries = Array.from(dataSource.values());
            else if (Array.isArray(dataSource)) entries = dataSource;
            else entries = Object.values(dataSource);

            let allSegments = [];
            for (const entry of entries) {
                if (Array.isArray(entry) && entry.length > 0 && entry[0].id !== undefined) {
                    allSegments = allSegments.concat(entry);
                } else if (entry && typeof entry === 'object' && entry.id && !Array.isArray(entry)) {
                    allSegments.push(entry);
                }
            }

            let uniqueSegments = new Map();
            for (const seg of allSegments) {
                if (seg.id && seg.name && !seg.name.toLowerCase().includes('finish')) {
                    uniqueSegments.set(seg.id, seg);
                }
            }

            if (uniqueSegments.size === 0) return;

            let newSprintLeaders = new Map();
            let newKomLeaders = new Map();
            let newLapLeaders = new Map();

            for (const seg of uniqueSegments.values()) {
                try {
                    let results = null;
                    if (common.rpc && typeof common.rpc.getSegmentResults === 'function') {
                        results = await common.rpc.getSegmentResults(seg.id);
                    }

                    if (results) {
                        results = results.filter(r => {
                            const athId = Number(r.athleteId || r.zwid || r.id);

                            if (cachedEventStart) {
                                let resultTime = r.ts || r.timestamp || r.endTime || 0;
                                if (resultTime > 0 && resultTime < 20000000000) resultTime *= 1000; 
                                if (resultTime > 0 && resultTime <= cachedEventStart) {
                                    return false;
                                }
                            }

                            if (cachedSubgroupId) {
                                let rSubId = r.eventSubgroupId || r.subgroupId || (r.state && r.state.eventSubgroupId) || (r.state && r.state.subgroupId);
                                
                                if (rSubId === undefined && knownEventRiders.has(athId)) {
                                    rSubId = knownEventRiders.get(athId);
                                }
                                
                                if (rSubId === undefined) {
                                    const fullAth = common.athletes && common.athletes.get(athId);
                                    if (fullAth && fullAth.state) {
                                        rSubId = fullAth.state.eventSubgroupId || fullAth.state.subgroupId;
                                        if (rSubId === undefined) rSubId = 0; 
                                    }
                                }

                                if (rSubId === undefined && athId === Number(common.athleteId) && common.athlete && common.athlete.state) {
                                    rSubId = common.athlete.state.eventSubgroupId || common.athlete.state.subgroupId;
                                }
                                
                                if (rSubId !== undefined && String(rSubId) !== String(cachedSubgroupId)) {
                                    return false; 
                                }
                            }
                            
                            return true;
                        });
                    }

                    if (results && results.length > 0) {
                        let ftsRes = results.slice().sort((a, b) => (a.elapsed || 99999999) - (b.elapsed || 99999999));
                        
                        let leaderMale = null;
                        let leaderFemale = null;

                        for (const r of ftsRes) {
                            let isFemale = false;
                            if (r.gender === 'female' || r.gender === 2 || r.male === false) isFemale = true;
                            else if (r.gender === 'male' || r.gender === 1 || r.male === true) isFemale = false;
                            else {
                                const athId = Number(r.athleteId || r.zwid || r.id);
                                const fullAth = common.athletes && common.athletes.get(athId);
                                if (fullAth && fullAth.athlete) {
                                    isFemale = (fullAth.athlete.gender === 'female' || fullAth.athlete.gender === 2 || fullAth.athlete.male === false);
                                }
                            }

                            if (isFemale && !leaderFemale) leaderFemale = r;
                            if (!isFemale && !leaderMale) leaderMale = r;
                            if (leaderMale && leaderFemale) break;
                        }

                        const processLeader = (leader) => {
                            if (leader) {
                                const leaderId = String(leader.athleteId || leader.zwid || leader.id);
                                const segNameUpper = seg.name.toUpperCase();
                                
                                if (segNameUpper.includes('KOM') || segNameUpper.includes('EPIC') || segNameUpper.includes('CLIMB')) {
                                    newKomLeaders.set(leaderId, (newKomLeaders.get(leaderId) || 0) + 1);
                                } else if (segNameUpper.includes('LAP') || segNameUpper.includes('ROUTE') || segNameUpper.includes('LOOP')) {
                                    newLapLeaders.set(leaderId, (newLapLeaders.get(leaderId) || 0) + 1);
                                } else {
                                    newSprintLeaders.set(leaderId, (newSprintLeaders.get(leaderId) || 0) + 1);
                                }
                            }
                        };

                        processLeader(leaderMale);
                        processLeader(leaderFemale);
                    }
                } catch (e) {
                    // Silencieux pour ne pas polluer
                }
            }

            activeSprintLeaders = newSprintLeaders;
            activeKOMLeaders = newKomLeaders;
            activeLapLeaders = newLapLeaders;
        });

        common.subscribe('nearby', updateRiders);
    }
}