window.attachChordHoverActions = attachChordHoverActions;
// Attach hover actions (delete, beat count, play on hover) to a chord element in instrumental section
function attachChordHoverActions(charElement, isFromDrop = false) {
    if (!charElement || !charElement.classList.contains('char') || !charElement.dataset.chord) return;
    // Remove previous listeners to prevent stacking
    if (charElement._mouseenterListener) {
        charElement.removeEventListener('mouseenter', charElement._mouseenterListener);
    }
    if (charElement._dropListener) {
        charElement.removeEventListener('drop', charElement._dropListener);
    }
    // If called from drop, immediately suppress hover to prevent playing chord
    let suppressNextHover = isFromDrop;
    
    // If a chord is just added via drop, suppress playback on the next hover
    const dropListener = () => {
        suppressNextHover = true;
        setTimeout(() => { suppressNextHover = false; }, 300);
    };
    charElement.addEventListener('drop', dropListener);
    charElement._dropListener = dropListener;
    
    // If this was called from a drop, set a longer timeout to ensure no play on hover
    if (isFromDrop) {
        setTimeout(() => { suppressNextHover = false; }, 500);
    }
    const mouseenterListener = () => {
        if (suppressNextHover) return;
        
        // Skip ALL hover actions (including play) if we're in toggle mode
        if (document.body.dataset.deleteMode === 'true' || document.body.dataset.beatMode === 'true') {
            return;
        }
        
        if (typeof dom !== 'undefined' && dom.playOnHoverCheckbox && dom.playOnHoverCheckbox.checked) {
            if (typeof previewChord === 'function') {
                previewChord(charElement.dataset.lookupName || charElement.dataset.chord);
            }
        }
        if (document.body.dataset.print === "true") return;
        let deleteIcon = charElement._deleteIcon;
        let beatBadge = charElement._beatBadge;
        let beats = charElement.dataset.beats ? parseInt(charElement.dataset.beats, 10) : 4;
       /* if (!deleteIcon) {
            // --- Delete Icon ---
            deleteIcon = document.createElement('span');
            deleteIcon.className = 'chord-lyrics-delete-btn';
            deleteIcon.innerHTML = '<i class="fas fa-trash"></i>';
            deleteIcon.title = 'Remove chord';
            // --- Beat Badge ---
            beatBadge = document.createElement('span');
            beatBadge.className = 'chord-beat-badge';
            beatBadge.textContent = beats;
            beatBadge.title = 'Beats (left-click: +1, right-click: -1)';
            charElement.style.position = 'relative';
            charElement.appendChild(deleteIcon);
            charElement.appendChild(beatBadge);
            charElement._deleteIcon = deleteIcon;
            charElement._beatBadge = beatBadge;

            // --- Hover Logic ---
            let hideTimeout;
            const showIcons = () => {
                // Don't show hover icons if we're in toggle mode
                if (document.body.dataset.deleteMode === 'true' || document.body.dataset.beatMode === 'true') {
                    return;
                }
                deleteIcon.style.display = 'block';
                beatBadge.style.display = 'flex';
            };
            const hideIcons = () => {
                hideTimeout = setTimeout(() => {
                    deleteIcon.style.display = 'none';
                    beatBadge.style.display = 'none';
                }, 100);
            };
            charElement.addEventListener('mouseleave', hideIcons);
            deleteIcon.addEventListener('mouseenter', () => {
                if (hideTimeout) clearTimeout(hideTimeout);
                showIcons();
            });
            deleteIcon.addEventListener('mouseleave', hideIcons);
            beatBadge.addEventListener('mouseenter', () => {
                if (hideTimeout) clearTimeout(hideTimeout);
                showIcons();
            });
            beatBadge.addEventListener('mouseleave', hideIcons);

            // --- Delete Action ---
            deleteIcon.addEventListener('click', (e) => {
                e.stopPropagation();
                // Remove chord from char span (new system)
                charElement.removeAttribute('data-chord');
                charElement.removeAttribute('data-beats');
                deleteIcon.remove();
                beatBadge.remove();
            });

            // --- Beat Badge Actions ---
            beatBadge.addEventListener('click', (e) => {
                e.stopPropagation();
                beats = Math.min(beats + 1, 8);
                charElement.dataset.beats = beats;
                beatBadge.textContent = beats;
                // Enable save button when beats change
                if (window.enableSave) window.enableSave();
            });
            beatBadge.addEventListener('contextmenu', (e) => {
                e.preventDefault();
                e.stopPropagation();
                beats = Math.max(beats - 1, 1);
                charElement.dataset.beats = beats;
                beatBadge.textContent = beats;
                // Enable save button when beats change
                if (window.enableSave) window.enableSave();
            });
        } else {
            deleteIcon.style.display = 'block';
            beatBadge.style.display = 'flex';
        }*/
    };
    charElement.addEventListener('mouseenter', mouseenterListener);
    charElement._mouseenterListener = mouseenterListener;
}

// Utility: Ensure all text nodes in .lyrics-editor are wrapped in .char spans
export function ensureCharSpansInLyricsEditor(editorDiv) {
    if (!editorDiv) return;
    console.log('ensureCharSpansInLyricsEditor called');
    
    // Helper function to process nodes and convert text to char spans
    const processNodes = (container) => {
        Array.from(container.childNodes).forEach(node => {
            // Split raw text nodes into .char spans
            if (node.nodeType === Node.TEXT_NODE && node.textContent.trim() !== '') {
                const frag = document.createDocumentFragment();
                for (const char of node.textContent) {
                    frag.appendChild(createCharSpan(char));
                }
                container.replaceChild(frag, node);
            }
            // Only split .char spans with >1 character if NOT a chord
            else if (node.nodeType === Node.ELEMENT_NODE && node.classList.contains('char') && node.textContent.length > 1 && !node.dataset.chord) {
                const frag = document.createDocumentFragment();
                for (const char of node.textContent) {
                    frag.appendChild(createCharSpan(char));
                }
                container.replaceChild(frag, node);
            }
            // If .char span has data-chord, preserve as-is
        });
    };
    
    // Process content within div elements (multi-line content)
    editorDiv.querySelectorAll('div').forEach(lineDiv => {
        processNodes(lineDiv);
    });
    
    // Also process direct children of the editor (single-line content without divs)
    processNodes(editorDiv);
    // Attach dragover/drop listeners to all .char spans
    //attachCharDropListeners(editorDiv);
}
// DOM-only transpose logic
export function transposeAllChordsDOM(direction = 1, preferFlat = false) {
    console.log(`transposeAllChordsDOM called: direction=${direction}, preferFlat=${preferFlat}`);
    
    // First, rebuild currentChordsMap from DOM before transposing
    window.currentChordsMap = new Map();
    const allChords = document.querySelectorAll('.char[data-chord]');
    allChords.forEach(charSpan => {
        const lookupName = charSpan.dataset.lookupName || charSpan.dataset.chord;
        if (lookupName && lookupName.trim()) {
            window.currentChordsMap.set(lookupName, lookupName);
        }
    });
    console.log(`Rebuilt currentChordsMap from DOM. Size: ${window.currentChordsMap.size}`);
    
    // Helper: get transposed chord name
    function transposeChordNameDOM(name, direction = 1, preferFlat = false) {
        const CHORD_ROOTS = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'];
        const SHARP_TO_FLAT = { 'C#': 'Db', 'D#': 'Eb', 'F#': 'Gb', 'G#': 'Ab', 'A#': 'Bb' };
        const FLAT_TO_SHARP = { 'Db': 'C#', 'Eb': 'D#', 'Gb': 'F#', 'Ab': 'G#', 'Bb': 'A#', 'Cb': 'B', 'Fb': 'E' };
        function getChordRootAndSuffix(name) {
            const match = name.match(/^([A-G][b#]?)(.*)$/);
            if (!match) return [name, ''];
            return [match[1], match[2]];
        }
        let [root, suffix] = getChordRootAndSuffix(name);
        if (FLAT_TO_SHARP[root]) root = FLAT_TO_SHARP[root];
        let idx = CHORD_ROOTS.indexOf(root);
        if (idx === -1) return name;
        let newIdx = (idx + direction + 12) % 12;
        let newRoot = CHORD_ROOTS[newIdx];
        if (preferFlat && SHARP_TO_FLAT[newRoot]) {
            newRoot = SHARP_TO_FLAT[newRoot];
        }
        return newRoot + suffix;
    }
    console.log('transposeAllChordsDOM called');
    let totalChords = 0, updatedChords = 0, editorsFound = 0, instrumentalCellsFound = 0;
    
    // Transpose chords in lyrics editors
    const editors = document.querySelectorAll('.lyrics-editor');
    if (editors.length === 0) {
        console.warn('transposeAllChordsDOM: No .lyrics-editor elements found');
    }
    editors.forEach(editorDiv => {
        editorsFound++;
        const chordChars = editorDiv.querySelectorAll('.char[data-chord]');
        if (chordChars.length === 0) {
            console.warn('transposeAllChordsDOM: No .char[data-chord] elements found in one .lyrics-editor');
        }
        chordChars.forEach(charSpan => {
            totalChords++;
            if (!charSpan || !charSpan.dataset) return;
            const chordName = charSpan.dataset.chord;
            console.log(`Processing chord: "${chordName}" (type: ${typeof chordName})`);
            // Always normalize to ASCII before transposing (handle both Unicode and HTML entities)
            const asciiLookup = chordName
                .replace(/♭/g, 'b').replace(/♯/g, '#')
                .replace(/&#9837;/g, 'b').replace(/&#9839;/g, '#');
            console.log(`ASCII lookup: "${asciiLookup}"`);
            const transposed = transposeChordNameDOM(asciiLookup, direction, preferFlat);
            console.log(`Transposed: "${transposed}"`);
            // Ensure ASCII for lookup name
            const asciiTransposed = transposed.replace(/♭/g, 'b').replace(/♯/g, '#');
            // Store ASCII version in dataset for future transpositions
            charSpan.dataset.chord = asciiTransposed;
            // Update lookupName for chord playback
            charSpan.dataset.lookupName = asciiTransposed;
            // Update chord display element if it exists
            const chordDisplayEl = charSpan.querySelector('.chord-display');
            if (chordDisplayEl) {
                chordDisplayEl.innerHTML = displayChordName(asciiTransposed);
            }
            updatedChords++;
        });
    });

    // Transpose chords in instrumental sections
    const instrumentalCells = document.querySelectorAll('.instrumental-cell .char[data-chord]');
    instrumentalCellsFound = instrumentalCells.length;
    instrumentalCells.forEach(charSpan => {
        totalChords++;
        if (!charSpan || !charSpan.dataset) return;
        const chordName = charSpan.dataset.chord;
        // Always normalize to ASCII before transposing (handle both Unicode and HTML entities)
        const asciiLookup = chordName
            .replace(/♭/g, 'b').replace(/♯/g, '#')
            .replace(/&#9837;/g, 'b').replace(/&#9839;/g, '#');
        const transposed = transposeChordNameDOM(asciiLookup, direction, preferFlat);
        // Ensure ASCII for lookup name
        const asciiTransposed = transposed.replace(/♭/g, 'b').replace(/♯/g, '#');
        // Store ASCII version in dataset for future transpositions
        charSpan.dataset.chord = asciiTransposed;
        // Update lookupName for chord playback
        charSpan.dataset.lookupName = asciiTransposed;
        // Update chord display element if it exists
        const displayName = typeof window.displayChordName === 'function'
            ? window.displayChordName(asciiTransposed)
            : asciiTransposed;
        const chordDisplayEl = charSpan.querySelector('.chord-display');
        if (chordDisplayEl) {
            chordDisplayEl.innerHTML = displayName;
        } else {
            // For instrumental sections without chord-display element, update innerHTML directly
            charSpan.innerHTML = displayName;
        }
        updatedChords++;
    });

    console.log(`transposeAllChordsDOM: editors found: ${editorsFound}, instrumental cells found: ${instrumentalCellsFound}, chords found: ${totalChords}, chords updated: ${updatedChords}`);
    
    // After transposing all chords, update currentChordsMap and fetch new chord data
    if (updatedChords > 0) {
        // Update window.currentChordsMap with transposed chord names
        if (window.currentChordsMap instanceof Map) {
            console.log(`Updating currentChordsMap. Current size: ${window.currentChordsMap.size}`);
            const newMap = new Map();
            function toAscii(name) { 
                return name.replace(/♭/g, 'b').replace(/♯/g, '#')
                           .replace(/&#9837;/g, 'b').replace(/&#9839;/g, '#'); 
            }
            for (const [normalized, original] of window.currentChordsMap.entries()) {
                console.log(`Transposing map entry: "${normalized}" -> "${original}"`);
                // Convert to ASCII before transposing to handle HTML entities
                const normalizedAscii = toAscii(normalized);
                const originalAscii = toAscii(original);
                const transposedNorm = transposeChordNameDOM(normalizedAscii, direction, preferFlat);
                const transposedOrig = transposeChordNameDOM(originalAscii, direction, preferFlat);
                console.log(`Result: "${transposedNorm}" -> "${transposedOrig}"`);
                // Store ASCII versions in the map (no HTML entities)
                newMap.set(transposedNorm, transposedOrig);
            }
            window.currentChordsMap = newMap;
            console.log(`Updated currentChordsMap. New size: ${window.currentChordsMap.size}`);
            
            // Initialize chord data for the transposed chords (use ASCII names)
            if (typeof window.initializeChordData === 'function') {
                const chordNames = Array.from(newMap.keys());
                window.initializeChordData(chordNames).then(apiChords => {
                    // Build toolbar map using transposed names (newMap already contains ASCII)
                    const toolbarMap = new Map();
                    for (const [norm, orig] of newMap.entries()) {
                        // norm and orig are already ASCII from the newMap
                        // Use ASCII for SVG titles to avoid UTF-8 encoding issues, visual symbols handled by CSS
                        const displayName = preferFlat ? convertToFlat(norm) : convertToSharp(norm);
                        const chordData = apiChords.find(c => c.chordName === norm || c.chordName === convertToSharp(norm) || c.chordName === convertToFlat(norm));
                        if (chordData) {
                            toolbarMap.set(chordData.chordName, displayName);
                        }
                    }
                    // Update chord API data and toolbar
                    state.setChordApiData(apiChords);
                    if (typeof renderChordsInToolbar === 'function') {
                        renderChordsInToolbar(toolbarMap);
                    }
                }).catch(error => {
                    console.error('Error initializing chord data after transpose:', error);
                });
            }
        }
    }
}

window.transposeAllChordsDOM = transposeAllChordsDOM;
// Convert ASCII chord name to sharp
export function convertToSharp(name) {
    const FLAT_TO_SHARP = { 'Db': 'C#', 'Eb': 'D#', 'Gb': 'F#', 'Ab': 'G#', 'Bb': 'A#', 'Cb': 'B', 'Fb': 'E' };
    const match = name.match(/^([A-G]b)(.*)$/);
    if (match && FLAT_TO_SHARP[match[1]]) {
        return FLAT_TO_SHARP[match[1]] + match[2];
    }
    return name;
}

// Convert ASCII chord name to flat
export function convertToFlat(name) {
    const SHARP_TO_FLAT = { 'C#': 'Db', 'D#': 'Eb', 'F#': 'Gb', 'G#': 'Ab', 'A#': 'Bb' };
    const match = name.match(/^([A-G]#)(.*)$/);
    if (match && SHARP_TO_FLAT[match[1]]) {
        return SHARP_TO_FLAT[match[1]] + match[2];
    }
    return name;
}
import * as dom from './dom.js';
import * as state from './state.js';
import { renderSidePanel } from './ui.js';
import { previewChord } from './audio.js';
import { renderChordsInToolbar } from './chords.js';

// --- Helper Functions ---
// For display only: return ASCII chord names (b/#) to avoid UTF-8 encoding issues
export function displayChordName(name) {
    // Return the chord name as-is with ASCII characters (b/#)
    return name;
}

// Expose displayChordName to global scope
window.displayChordName = displayChordName;

const debounce = (func, delay) => {
    let timeout;
    return function(...args) {
        clearTimeout(timeout);
        timeout = setTimeout(() => func.apply(this, args), delay);
    };
};

const flatToSharpMap = {
    'Bb': 'A#',
    'Eb': 'D#',
    'Ab': 'G#',
    'Db': 'C#',
    'Gb': 'F#',
    'Cb': 'B',
    'Fb': 'E'
};



export function normalizeChordName(name) {
    const root = name.slice(0, 2);
    if (flatToSharpMap[root]) {
        return flatToSharpMap[root] + name.slice(2);
    }
    
    const root2 = name.slice(0, 1);
     if (flatToSharpMap[root2]) {
        return flatToSharpMap[root2] + name.slice(1);
    }

    return name;
}

export const generateId = () => 's' + Date.now() + Math.random();

export const createCharSpan = (char) => {
    const span = document.createElement('span');
    span.className = 'char';
    span.textContent = char;
    return span;
};

const setCursorAfter = (node, editor) => {
    const selection = window.getSelection();
    const newRange = document.createRange();
    if (node) {
        newRange.setStartAfter(node);
    } else {
        newRange.setStart(editor, 0);
    }
    newRange.collapse(true);
    selection.removeAllRanges();
    selection.addRange(newRange);
};

export const parseChordPro = (text) => {
    let html = '';
    const regex = /(\[[^\]]+\])|([^\s\[\]]+)|(\s+)/g;
    let match;
    const tokens = [];
    
    while ((match = regex.exec(text)) !== null) {
        if (match[1]) {
            // Support [Chord;Beats] format
            const chordContent = match[1].slice(1, -1);
            const chordParts = chordContent.split(';');
            const originalChord = chordParts[0];
            const beats = chordParts.length > 1 ? chordParts[1] : null;
            const normalizedChord = normalizeChordName(originalChord);
            tokens.push({ type: 'chord', original: originalChord, normalized: normalizedChord, beats });
        }
        else if (match[2]) tokens.push({ type: 'lyric', value: match[2] });
        else if (match[3]) tokens.push({ type: 'space', value: match[3] });
    }

    const processedTokens = [];
    for (let i = 0; i < tokens.length; i++) {
        const token = tokens[i];
        
        if (token.type === 'chord') {
            // Look ahead to find the next non-space token
            let nextNonSpaceIndex = i + 1;
            while (nextNonSpaceIndex < tokens.length && tokens[nextNonSpaceIndex].type === 'space') {
                nextNonSpaceIndex++;
            }
            
            const nextNonSpaceToken = (nextNonSpaceIndex < tokens.length) ? tokens[nextNonSpaceIndex] : null;
            
            if (nextNonSpaceToken && nextNonSpaceToken.type === 'lyric') {
                // Add any intermediate spaces to processed tokens
                for (let j = i + 1; j < nextNonSpaceIndex; j++) {
                    processedTokens.push(tokens[j]);
                }
                
                let lyric = nextNonSpaceToken.value;
                processedTokens.push({ type: 'chord-lyric', chord: token.normalized, original: token.original, lyric: lyric, beats: token.beats });
                i = nextNonSpaceIndex; // Skip to the lyric token we just processed
            } else {
                processedTokens.push({ type: 'instrumental-chord', chord: token.normalized, original: token.original, beats: token.beats });
            }
        } else {
            processedTokens.push(token);
        }
    }

    processedTokens.forEach(token => {
        if (token.type === 'chord-lyric') {
            // Set data-chord and data-beats on the first lyric character
            // Store ASCII chord name in data-chord for consistent lookup
            const displayName = displayChordName(token.original);
            html += `<span class="char has-chord-display" data-chord="${token.original}"${token.beats ? ` data-beats="${token.beats}"` : ''}><span class="chord-display">${displayName}</span>${token.lyric[0]}</span>`;
            for (let j = 1; j < token.lyric.length; j++) {
                html += createCharSpan(token.lyric[j]).outerHTML;
            }
        } else if (token.type === 'instrumental-chord') {
            // Store ASCII chord name in data-chord for consistent lookup
            const displayName = displayChordName(token.original);
            html += `<span class="char has-chord-display" data-chord="${token.original}"${token.beats ? ` data-beats="${token.beats}"` : ''}><span class="chord-display">${displayName}</span>\u00A0</span>`;
        } else if (token.type === 'lyric' || token.type === 'space') {
            for(const char of token.value) {
                html += createCharSpan(char).outerHTML;
            }
        }
    });
    
    return html;
};

// --- Core Application Logic ---
// Transpose all chords in song sections and toolbar
export async function transposeAllChords(direction = 1) {
    const preferFlats = window.preferFlats === true;
    function toAscii(name) { return convertToSharp(name.replace(/♭/g, 'b').replace(/♯/g, '#')); }
    for (const section of state.songSections) {
        if (!section.content) continue;
        section.content = section.content.replace(/<span class="chord" data-lookup-name="([^"]+)">([^<]+)<\/span>/g,
            (match, lookupName, displayName) => {
                const transposedLookup = transposeChordName(toAscii(lookupName), direction, preferFlats);
                const transposedDisplay = displayChordName(transposedLookup);
                return `<span class="chord" data-lookup-name="${transposedLookup}">${transposedDisplay}</span>`;
            }
        );
    }
    let newMap = new Map();
    if (window.currentChordsMap instanceof Map) {
        newMap = new Map();
        for (const [normalized, original] of window.currentChordsMap.entries()) {
            const transposedNorm = transposeChordName(toAscii(normalized), direction, preferFlats);
            const transposedOrig = transposeChordName(toAscii(original), direction, preferFlats);
            newMap.set(transposedNorm, transposedOrig);
        }
        window.currentChordsMap = newMap;
    }
    // Guarantee only ASCII chord names are used for API search
    if (typeof window.initializeChordData === 'function') {
        const chordNames = Array.from(newMap.keys()).map(toAscii);
        const apiChords = await window.initializeChordData(chordNames);
        // Build toolbar map using transposed names
        const toolbarMap = new Map();
        for (const [norm, disp] of newMap.entries()) {
            const normAscii = toAscii(norm);
            const displayName = window.preferFlats
                ? displayChordName(convertToFlat(normAscii))
                : displayChordName(convertToSharp(normAscii));
            const chordData = apiChords.find(c => toAscii(c.chordName) === normAscii);
            if (chordData) {
                toolbarMap.set(chordData.chordName, displayName);
            }
        }
        if (typeof window.setChordApiData === 'function') {
            window.setChordApiData(apiChords);
        }
        if (typeof renderChordsInToolbar === 'function') {
            renderChordsInToolbar(toolbarMap);
        }
    } else if (typeof renderChordsInToolbar === 'function') {
        renderChordsInToolbar(newMap);
    }
}

// When creating chord buttons, store the UUID if available
const createChordButton = (chordName, chordData = null) => {
    const button = document.createElement('div');
    button.className = 'chord-button';
    button.innerHTML = chordName;
    button.draggable = true;
    
    // Store UUID if chord data is available
    if (chordData && chordData.uuid) {
        button.dataset.uuid = chordData.uuid;
    } else if (chordData && chordData.id) {
        button.dataset.uuid = chordData.id;
    }
    
    // Add drag handlers
    attachDragHandlerToChord(button);
    
    return button;
};

// When loading chords from API, preserve UUID information
const loadChordFromAPI = async (chordName) => {
    try {
        if (typeof window.searchChordByName === 'function') {
            const results = await window.searchChordByName(chordName);
            if (results && results.length > 0) {
                return results[0]; // Return first match with UUID
            }
        }
    } catch (error) {
        console.error('Error loading chord from API:', error);
    }
    return null;
};

const saveSectionContent = (sectionId, content) => {
    const section = state.songSections.find(s => s.id === sectionId);
    if (section) {
        section.content = content;
    }
};
const debouncedSave = debounce(saveSectionContent, 300);

export const deleteSection = (sectionId) => {
     if (confirm('Are you sure you want to delete this section?')) {
        document.getElementById(sectionId)?.remove();
    }
};


export function attachDragHandlerToChord(chordElement) {
    chordElement.setAttribute('draggable', 'true');
    chordElement.addEventListener('dragstart', (e) => {
        e.stopPropagation();
        const data = JSON.stringify({
            display: e.target.dataset.lookupName || e.target.dataset.chord,
            lookup: e.target.dataset.lookupName
        });
        e.dataTransfer.setData('application/json', data);
        e.dataTransfer.effectAllowed = 'move';
        state.setDraggedChordSourceElement(e.target.parentNode);
    });

    // Only render delete/beat icons if not in print mode
    chordElement.addEventListener('mouseenter', () => {
        // Skip ALL hover actions (including play) if we're in toggle mode
        if (document.body.dataset.deleteMode === 'true' || document.body.dataset.beatMode === 'true') {
            return;
        }
        
        if (dom.playOnHoverCheckbox.checked) {
            previewChord(chordElement.dataset.lookupName);
        }
        if (document.body.dataset.print === "true") return;
        const chordContainer = chordElement.parentNode;
        if (!chordContainer._deleteIcon) {
            // --- Delete Icon ---
            const deleteIcon = document.createElement('span');
            deleteIcon.className = 'chord-lyrics-delete-btn';
            deleteIcon.innerHTML = '<i class="fas fa-trash"></i>';
            deleteIcon.title = 'Remove chord';

            // --- Beat Badge ---
            const beatBadge = document.createElement('span');
            beatBadge.className = 'chord-beat-badge';
            let beats = chordElement.dataset.beats ? parseInt(chordElement.dataset.beats, 10) : 4;
            beatBadge.textContent = beats;
            beatBadge.title = 'Beats (left-click: +1, right-click: -1)';

            chordContainer.style.position = 'relative';
            chordContainer.appendChild(deleteIcon);
            chordContainer.appendChild(beatBadge);
            chordContainer._deleteIcon = deleteIcon;
            chordContainer._beatBadge = beatBadge;

            // --- Hover Logic ---
            let hideTimeout;
            const showIcons = () => {
                // Don't show hover icons if we're in toggle mode
                if (document.body.dataset.deleteMode === 'true' || document.body.dataset.beatMode === 'true') {
                    return;
                }
                deleteIcon.style.display = 'block';
                beatBadge.style.display = 'flex';
            };
            const hideIcons = () => {
                hideTimeout = setTimeout(() => {
                    deleteIcon.style.display = 'none';
                    beatBadge.style.display = 'none';
                }, 100);
            };
            chordElement.addEventListener('mouseleave', hideIcons);
            deleteIcon.addEventListener('mouseenter', () => {
                if (hideTimeout) clearTimeout(hideTimeout);
                showIcons();
            });
            deleteIcon.addEventListener('mouseleave', hideIcons);
            beatBadge.addEventListener('mouseenter', () => {
                if (hideTimeout) clearTimeout(hideTimeout);
                showIcons();
            });
            beatBadge.addEventListener('mouseleave', hideIcons);

            // --- Delete Action ---
            deleteIcon.addEventListener('click', (e) => {
                e.stopPropagation();
                if (chordContainer.classList.contains('chord-container')) {
                    const charSpan = chordContainer.querySelector('.char');
                    if (charSpan) {
                        chordContainer.parentNode.replaceChild(charSpan, chordContainer);
                    } else {
                        chordContainer.remove();
                    }
                }
            });

            // --- Beat Badge Actions ---
            beatBadge.addEventListener('click', (e) => {
                e.stopPropagation();
                beats = Math.min(beats + 1, 8);
                chordElement.dataset.beats = beats;
                beatBadge.textContent = beats;
                // Enable save button when beats change
                if (window.enableSave) window.enableSave();
            });
            beatBadge.addEventListener('contextmenu', (e) => {
                e.preventDefault();
                e.stopPropagation();
                beats = Math.max(beats - 1, 1);
                chordElement.dataset.beats = beats;
                beatBadge.textContent = beats;
                // Enable save button when beats change
                if (window.enableSave) window.enableSave();
            });
        } else {
            chordContainer._deleteIcon.style.display = 'block';
            chordContainer._beatBadge.style.display = 'flex';
        }
    });
};

function attachEditorListeners(editor, sectionId) {
    console.log('attachEditorListeners called', { editor, sectionId });
    editor.addEventListener('input', (e) => {
        console.log('lyrics-editor input event fired', { sectionId, value: e.target.innerHTML });
        debouncedSave(sectionId, e.target.innerHTML);
    });
    editor.addEventListener('blur', () => {
        ensureCharSpansInLyricsEditor(editor);
    });
    // Single drop event for the lyrics editor
    editor.addEventListener('dragover', (e) => {
        e.preventDefault();
    });
    editor.addEventListener('drop', (e) => {
        e.preventDefault();
        // Find the nearest .char span
        const targetCharSpan = e.target.closest('.char');
        if (!targetCharSpan || !editor.contains(targetCharSpan)) {
            console.log('Drop ignored: no valid .char span found.');
            return;
        }
        let displayChord, lookupChord, beats;
        const jsonData = e.dataTransfer.getData('application/json');
        if (jsonData) {
            const data = JSON.parse(jsonData);
            displayChord = data.display;
            lookupChord = data.lookup;
            beats = data.beats;
        } else {
            const rawName = e.dataTransfer.getData('text/plain');
            displayChord = rawName;
            lookupChord = normalizeChordName(rawName);
        }
        // Set chord directly on .char span
        targetCharSpan.setAttribute('data-chord', displayChord);
        targetCharSpan.dataset.lookupName = lookupChord;
        if (beats) {
            targetCharSpan.setAttribute('data-beats', beats);
        } else {
            targetCharSpan.removeAttribute('data-beats');
        }
        // Pass true flag to indicate this is from a drop operation
        if (window.attachChordHoverActions) window.attachChordHoverActions(targetCharSpan, true);
    });
}

export function transposeChordNameDOM(name, direction = 1, preferFlat = false) {
    const CHORD_ROOTS = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'];
    const SHARP_TO_FLAT = { 'C#': 'Db', 'D#': 'Eb', 'F#': 'Gb', 'G#': 'Ab', 'A#': 'Bb' };
    const FLAT_TO_SHARP = { 'Db': 'C#', 'Eb': 'D#', 'Gb': 'F#', 'Ab': 'G#', 'Bb': 'A#', 'Cb': 'B', 'Fb': 'E' };
    function getChordRootAndSuffix(name) {
        const match = name.match(/^([A-G][b#]?)(.*)$/);
        if (!match) return [name, ''];
        return [match[1], match[2]];
    }
    let [root, suffix] = getChordRootAndSuffix(name);
    if (FLAT_TO_SHARP[root]) root = FLAT_TO_SHARP[root];
    let idx = CHORD_ROOTS.indexOf(root);
    if (idx === -1) return name;
    let newIdx = (idx + direction + 12) % 12;
    let newRoot = CHORD_ROOTS[newIdx];
    if (preferFlat && SHARP_TO_FLAT[newRoot]) {
        newRoot = SHARP_TO_FLAT[newRoot];
    }
    return newRoot + suffix;
}
window.transposeChordNameDOM = transposeChordNameDOM;
window.attachEditorListeners = attachEditorListeners;
window.attachChordHoverActions = attachChordHoverActions;

//# sourceMappingURL=app.js.map