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

// --- SCANNER DE BASE DE DONNÉES INTERNE (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();
let eventSubgroupsMap = {};

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; 
}

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);
    }

    if (cat && subId && cat !== 'E') {
        eventSubgroupsMap[subId] = cat;
    }

    if (!cat && subId && eventSubgroupsMap[subId] !== undefined) {
        cat = toLetter(eventSubgroupsMap[subId]);
    }

    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'; }
    
    return `<span style="background-color:${bg}; color:${color}; padding: 1px 4px; border-radius: 3px; font-weight: 900; font-size: 10px; margin-right: 2px; box-shadow: 0 1px 2px rgba(0,0,0,0.5);">${cat}</span>`;
}

// --- SETTINGS ---
let settings = {
    opacity: 90,
    zoom: 100,
    groupGapThreshold: 2, 
    refreshRate: 1,
    nearbyCount: 4 
};

let lastUpdate = 0; 

function loadSettings() {
    const sOp = localStorage.getItem('myMod_DS_Op');
    const sZoom = localStorage.getItem('myMod_DS_Zoom');
    const sRef = localStorage.getItem('myMod_DS_Refresh'); 
    const sNear = localStorage.getItem('myMod_DS_Nearby'); 
    
    if(sOp) settings.opacity = parseInt(sOp);
    if(sZoom) settings.zoom = parseInt(sZoom);
    if(sRef) settings.refreshRate = parseInt(sRef);
    if(sNear) settings.nearbyCount = parseInt(sNear);

    document.getElementById('in-opacity').value = settings.opacity;
    document.getElementById('in-zoom').value = settings.zoom;
    document.getElementById('in-refresh').value = settings.refreshRate;
    document.getElementById('in-nearby').value = settings.nearbyCount;

    document.getElementById('refresh-label').innerText = settings.refreshRate + 's';
    document.getElementById('nearby-label').innerText = settings.nearbyCount;
    
    applyVisuals();
}

function saveSettings() {
    settings.opacity = parseInt(document.getElementById('in-opacity').value);
    settings.zoom = parseInt(document.getElementById('in-zoom').value);
    settings.refreshRate = parseInt(document.getElementById('in-refresh').value);
    settings.nearbyCount = parseInt(document.getElementById('in-nearby').value);
    
    localStorage.setItem('myMod_DS_Op', settings.opacity);
    localStorage.setItem('myMod_DS_Zoom', settings.zoom);
    localStorage.setItem('myMod_DS_Refresh', settings.refreshRate);
    localStorage.setItem('myMod_DS_Nearby', settings.nearbyCount);

    applyVisuals();
    document.getElementById('settings-panel').style.display = 'none';
}

function applyVisuals() {
    document.getElementById('op-label').innerText = settings.opacity;
    document.getElementById('dash').style.backgroundColor = `rgba(0, 0, 0, ${settings.opacity/100})`;
    document.getElementById('zoom-label').innerText = (settings.zoom/100).toFixed(1);
    document.getElementById('wrapper').style.transform = `scale(${settings.zoom/100})`;
}

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);
    return `hsl(${Math.abs(hash) % 360}, 80%, 70%)`;
}

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 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 formatName(first, last) {
    if (!last) return first || 'Inconnu';
    let cleanLast = last.replace(/\[.*?\]|\(.*?\)/g, '').trim();
    const fInitial = first ? first.charAt(0).toUpperCase() + '.' : '';
    return `${fInitial} ${cleanLast.toUpperCase()}`;
}

// --- ZWIFT LOGIC ---
function updateGroups(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) {
            document.getElementById('groups-container').innerHTML = '<div class="msg">Aucune donnée...</div>';
            return;
        }

        const watchedRiders = JSON.parse(localStorage.getItem('myMod_WatchedRiders')) || [];
        const watchedTeams = JSON.parse(localStorage.getItem('myMod_WatchedTeams')) || [];

        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();
            myTeamName = tName;
        }

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

        let groups = [];
        let myGroupIndex = -1; 

        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 > settings.groupGapThreshold) {
                    if (currentGroup.some(r => r.watching)) myGroupIndex = groups.length;
                    groups.push(currentGroup);
                    currentGroup = [r];
                } else {
                    currentGroup.push(r);
                }
            }
            if (currentGroup.some(r => r.watching)) myGroupIndex = groups.length;
            groups.push(currentGroup);
        }

        const groupsAvgGap = groups.map(grp => {
            const sum = grp.reduce((acc, r) => acc + (r.gap || 0), 0);
            return sum / grp.length;
        });

        let myGroupGapRef = 0;
        if (myGroupIndex !== -1) {
            myGroupGapRef = groupsAvgGap[myGroupIndex];
        } else {
            myGroupIndex = Math.floor(groups.length / 2);
        }

        let indicesToShow = new Set();
        indicesToShow.add(0); 
        indicesToShow.add(groups.length - 1); 

        const scope = settings.nearbyCount;
        for (let i = myGroupIndex - scope; i <= myGroupIndex + scope; i++) {
            if (i >= 0 && i < groups.length) {
                indicesToShow.add(i);
            }
        }

        let sortedIndices = Array.from(indicesToShow).sort((a, b) => a - b);

        let html = '';
        
        for (let k = 0; k < sortedIndices.length; k++) {
            const index = sortedIndices[k];
            const group = groups[index];

            if (k > 0) {
                const prevIndexShown = sortedIndices[k - 1];
                const gapIndices = index - prevIndexShown - 1; 
                
                if (gapIndices > 0) {
                    html += `
                        <div style="text-align:center; padding:5px; background:rgba(255,255,255,0.05); margin:2px 0; font-size:11px; color:#888; border-radius:4px;">
                            ... ${gapIndices} groupe(s) intermédiaire(s) ...
                        </div>
                        <div class="link-arrow">▼</div>
                    `;
                } else {
                    html += `<div class="link-arrow">▼</div>`;
                }
            }

            let totalWkg = 0;
            let teamsMap = new Map();
            let colorsMap = new Map();
            let watchingInGroup = false;
            let catsInGroup = new Set();
            let watchedRidersInGroup = [];

            group.forEach(r => {
                let cat = detectCategory(r);
                if (cat && cat !== '-') catsInGroup.add(cat);

                const pwr = (r.state && r.state.power) || 0;
                const wgt = (r.athlete && r.athlete.weight) || 75;
                totalWkg += (pwr / wgt);

                let athleteId = (r.athlete && r.athlete.id) ? r.athlete.id : r.id;

                if (watchedRiders.includes(athleteId)) {
                    watchedRidersInGroup.push({
                        name: formatName(r.athlete?.firstName, r.athlete?.lastName),
                        lastName: r.athlete?.lastName || 'Inconnu',
                        id: athleteId
                    });
                }

                if (r.athlete) {
                    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 (!tColor) tColor = stringToColorHSL(tName);

                    if (tName !== "Indépendant" && tName !== "") {
                        teamsMap.set(tName, (teamsMap.get(tName) || 0) + 1);
                        colorsMap.set(tName, tColor);
                    }
                }
                if (r.watching) watchingInGroup = true;
            });

            const avgWkg = (totalWkg / group.length).toFixed(1);
            const sortedTeams = [...teamsMap.entries()].sort((a, b) => b[1] - a[1]);

            let catsHtml = '';
            if (catsInGroup.size > 0) {
                let sortedCats = Array.from(catsInGroup).sort();
                sortedCats.forEach(c => {
                    catsHtml += getCategoryBadge(c);
                });
            }

            let gapText = '';
            let gapClass = '';
            let myRelGapHtml = ''; 

            if (index === 0) {
                gapText = 'TÊTE';
                gapClass = 'gap-head';
            } else {
                const diff = groupsAvgGap[index] - groupsAvgGap[index - 1];
                gapText = '+ ' + formatTime(diff);
                gapClass = 'gap-chase';
            }

            if (!watchingInGroup && myGroupIndex !== -1) {
                const diffWithMe = groupsAvgGap[index] - myGroupGapRef;
                const absDiff = Math.abs(diffWithMe);
                const sign = diffWithMe > 0 ? '+' : '-'; 
                const relText = sign + ' ' + formatTime(absDiff);
                const relColor = diffWithMe > 0 ? '#ff5555' : '#44ff44'; 
                
                myRelGapHtml = `<div class="my-gap-badge" style="color:${relColor}">VS MOI : ${relText}</div>`;
            } else if (watchingInGroup) {
                 myRelGapHtml = `<div class="my-gap-badge" style="color:#fc6719; font-weight:bold;">MON GROUPE</div>`;
            }

            let cardClass = 'group-card';
            if (watchingInGroup) cardClass += ' watching-group';

            const firstRiderId = group[0].athleteId || group[0].id || (group[0].athlete && group[0].athlete.id);

            html += `
            <div class="${cardClass}" data-id="${firstRiderId}" title="Cliquer pour observer la tête de ce groupe">
                <div class="group-header">
                    <div class="group-info" style="display:flex; align-items:center; gap:6px;">
                        <span class="group-count">${group.length} 👤</span>
                        <span class="group-wkg">${avgWkg} w/kg</span>
                        <div class="group-cats">${catsHtml}</div>
                    </div>
                    <div class="group-gaps">
                        <div class="${gapClass}">${gapText}</div>
                        ${myRelGapHtml}
                    </div>
                </div>
                
                <div class="team-list">
            `;

            if (sortedTeams.length === 0 && watchedRidersInGroup.length === 0) {
                 html += `<div style="font-style:italic; color:#666; font-size:10px;">Indépendants</div>`;
            } else {
                // AFFICHAGE DES COUREURS SURVEILLÉS
                watchedRidersInGroup.forEach(wr => {
                    // Changement: seulement 4 lettres du nom de famille
                    let cleanLast = wr.lastName.replace(/\[.*?\]|\(.*?\)/g, '').trim();
                    const shortName = cleanLast.substring(0, 4).toUpperCase();
                    html += `
                        <div class="team-badge watched-rider" style="border-left: 3px solid #55ff55;" title="${wr.name}">
                            <span class="t-name">${shortName}</span>
                        </div>
                    `;
                });

                // AFFICHAGE DES ÉQUIPES
                sortedTeams.slice(0, 10).forEach(([name, count]) => {
                    const color = colorsMap.get(name);
                    const bg = color + '22'; 
                    const shortName = name.substring(0, 4).toUpperCase();
                    
                    let extraClass = '';
                    if (watchedTeams.includes(name)) {
                        extraClass = ' watched-team';
                    } else if (name === myTeamName && name !== "Indépendant") {
                        extraClass = ' my-team';
                    }

                    html += `
                        <div class="team-badge${extraClass}" style="border-left: 3px solid ${color}; background:${bg}; color:${color}" title="${name}">
                            <span class="t-count">${count}</span>
                            <span class="t-name">${shortName}</span>
                        </div>
                    `;
                });
                if (sortedTeams.length > 10) {
                    const remaining = sortedTeams.length - 10;
                    html += `<div class="team-badge" style="border-left: 3px solid #666; background:#333; color:#aaa; font-style:italic;">+${remaining}</div>`;
                }
            }
            html += `</div></div>`; 
        }

        document.getElementById('groups-container').innerHTML = html;
    } catch (err) {
        console.error(err);
    }
}

export async function main() {
    loadSettings();

    document.getElementById('btn-settings').addEventListener('click', () => {
        const p = document.getElementById('settings-panel');
        p.style.display = p.style.display === 'block' ? 'none' : 'block';
    });
    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();
    });
    
    document.getElementById('in-refresh').addEventListener('input', (e) => {
        settings.refreshRate = e.target.value;
        document.getElementById('refresh-label').innerText = settings.refreshRate + 's';
    });

    document.getElementById('in-nearby').addEventListener('input', (e) => {
        settings.nearbyCount = e.target.value;
        document.getElementById('nearby-label').innerText = settings.nearbyCount;
    });

    const groupsContainer = document.getElementById('groups-container');
    if (groupsContainer) {
        groupsContainer.addEventListener('click', async (e) => {
            const card = e.target.closest('.group-card');
            if (card && card.dataset.id) {
                const targetId = Number(card.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);
                }
            }
        });
    }

    if (common && common.initInteractionListeners) {
        common.initInteractionListeners();
        common.subscribe('nearby', updateGroups);
    }
}