import { chordApiData } from './state.js';
import { playStopBtn, timeSignatureSelect, loopCheckbox, tempoInput } from './dom.js';

// --- Tone.js Instrument & Metronome Setup ---
let currentInstrument;
let isInstrumentLoading = false;
let chordPlaybackPart;

// Expose the current instrument for external access
export function getCurrentInstrument() {
    return currentInstrument;
}

export function isInstrumentReady() {
    return currentInstrument && !isInstrumentLoading;
}

const metronomeClick = new Tone.NoiseSynth({
    noise: { type: 'white' },
    envelope: { attack: 0.001, decay: 0.05, sustain: 0, release: 0.1 }
}).toDestination();

const metronomeLoop = new Tone.Loop(time => {
    metronomeClick.triggerAttackRelease("32n", time);
}, "4n");

const TUNING = ['E2', 'A2', 'D3', 'G3', 'B3', 'E4'];
const NOTES = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'];

// --- Public Functions ---
export function initAudio() {
    let audioContextStarted = false;
    
    // Start audio context on any user interaction
    const startAudioContext = async (event) => {
        if (!audioContextStarted && Tone.context.state !== 'running') {
            try {
                await Tone.start();
                console.log('Audio context started');
                audioContextStarted = true;
                // Remove any audio prompt if it exists
                const audioPrompt = document.getElementById('audio-context-prompt');
                if (audioPrompt) {
                    audioPrompt.remove();
                }
            } catch (error) {
                console.log('Could not start audio context:', error);
            }
        }
    };
    
    // Listen for multiple interaction types to start audio context
    const interactionEvents = ['click', 'mousedown', 'keydown', 'touchstart'];
    
    interactionEvents.forEach(eventType => {
        document.body.addEventListener(eventType, startAudioContext, { once: true });
    });
    
    // Add a subtle prompt for audio activation
    setTimeout(() => {
        if (!audioContextStarted && Tone.context.state !== 'running') {
            showAudioPrompt();
        }
    }, 2000); // Show prompt after 2 seconds if no interaction
}

function showAudioPrompt() {
    // Only show if not already shown and audio context isn't running
    if (document.getElementById('audio-context-prompt') || Tone.context.state === 'running') {
        return;
    }
    
    const prompt = document.createElement('div');
    prompt.id = 'audio-context-prompt';
    prompt.innerHTML = `
        <div style="
            position: fixed;
            top: 20px;
            right: 20px;
            background: rgba(0, 123, 255, 0.9);
            color: white;
            padding: 10px 15px;
            border-radius: 6px;
            font-size: 14px;
            z-index: 10000;
            box-shadow: 0 2px 8px rgba(0,0,0,0.2);
            cursor: pointer;
            transition: opacity 0.3s ease;
        ">
            <i class="fas fa-volume-up" style="margin-right: 8px;"></i>
            Click anywhere to enable chord audio
        </div>
    `;
    
    // Make it clickable to activate audio
    prompt.addEventListener('click', async () => {
        try {
            await Tone.start();
            console.log('Audio context started from prompt');
            prompt.remove();
        } catch (error) {
            console.log('Could not start audio context:', error);
        }
    });
    
    document.body.appendChild(prompt);
    
    // Auto-hide after 10 seconds
    setTimeout(() => {
        if (prompt.parentNode) {
            prompt.style.opacity = '0';
            setTimeout(() => prompt.remove(), 300);
        }
    }, 10000);
}

// Function to ensure audio context is started (can be called from chord hover)
export async function ensureAudioContext() {
    if (Tone.context.state !== 'running') {
        try {
            await Tone.start();
            console.log('Audio context started');
        } catch (error) {
            console.log('Could not start audio context:', error);
        }
    }
}

export const fretToNote = (stringIndex, fret) => {
    const openNote = TUNING[stringIndex];
    const noteName = openNote.slice(0, -1);
    const octave = parseInt(openNote.slice(-1), 10);
    const startNoteIndex = NOTES.indexOf(noteName);
    const totalSteps = startNoteIndex + fret;
    const newNoteIndex = totalSteps % 12;
    const octaveOffset = Math.floor(totalSteps / 12);
    return NOTES[newNoteIndex] + (octave + octaveOffset);
};

export const getNotesFromVoicing = (chordName) => {
    // Try both sharp and flat forms
    function toFlat(name) {
        return name.replace(/C#/g, 'Db').replace(/D#/g, 'Eb').replace(/F#/g, 'Gb').replace(/G#/g, 'Ab').replace(/A#/g, 'Bb');
    }
    function toSharp(name) {
        return name.replace(/Db/g, 'C#').replace(/Eb/g, 'D#').replace(/Gb/g, 'F#').replace(/Ab/g, 'G#').replace(/Bb/g, 'A#');
    }
    let chordData = chordApiData.find(c => c.chordName === chordName);
    if (!chordData) {
        chordData = chordApiData.find(c => c.chordName === toFlat(chordName));
    }
    if (!chordData) {
        chordData = chordApiData.find(c => c.chordName === toSharp(chordName));
    }
    if (!chordData) {
        console.warn('No chordData found for', chordName);
        return [];
    }
    let frets = [0, 0, 0, 0, 0, 0];
    try {
        const barres = JSON.parse(chordData.barres);
        const fingers = JSON.parse(chordData.fingers);
        barres.forEach(barre => {
            const startString = Math.min(barre.fromString, barre.toString);
            const endString = Math.max(barre.fromString, barre.toString);
            for (let i = startString; i <= endString; i++) {
                const internalStringIndex = 6 - i;
                if (internalStringIndex >= 0 && internalStringIndex < 6) {
                    frets[internalStringIndex] = Math.max(frets[internalStringIndex], barre.fret);
                }
            }
        });
        fingers.forEach(([stringNum, fret]) => {
            const internalStringIndex = 6 - stringNum;
            if (internalStringIndex >= 0 && internalStringIndex < 6) {
                if (fret === 'x') {
                    frets[internalStringIndex] = 'x';
                } else {
                    frets[internalStringIndex] = Math.max(frets[internalStringIndex], fret);
                }
            }
        });
        const notes = frets
            .map((fret, stringIndex) => (fret !== 'x' ? fretToNote(stringIndex, fret) : null))
            .filter(Boolean);
        console.log('Chord', chordName, 'notes', notes);
        return notes;
    } catch (e) {
        console.error("Failed to parse chord voicing JSON for", chordName, e);
        return [];
    }
};

export const loadInstrument = (instrumentName) => {
    isInstrumentLoading = true;
    console.log(`Loading instrument: ${instrumentName}...`);
    try {
        currentInstrument = SampleLibrary.load({
              instruments: instrumentName,
              baseUrl: "https://nbrosowsky.github.io/tonejs-instruments/samples/",
              onload: () => {
                  isInstrumentLoading = false;
                  console.log(`${instrumentName} loaded successfully.`);
              }
        });
        currentInstrument.toDestination();
    } catch (error) {
        console.error(`Failed to load instrument: ${instrumentName}`, error);
        isInstrumentLoading = false;
    }
};

export const stopPlayback = () => {
    Tone.Transport.stop();
    Tone.Transport.cancel(0);
    metronomeLoop.stop(0);
    if (chordPlaybackPart) {
        chordPlaybackPart.stop(0);
        chordPlaybackPart.clear();
    }
    document.querySelectorAll('.chord.playing').forEach(el => el.classList.remove('playing'));
    playStopBtn.querySelector('i').classList.replace('fa-stop', 'fa-play');
};

export const startPlayback = () => {
    if (Tone.Transport.state === 'started') {
        stopPlayback();
        return;
    }

    const timeSignature = timeSignatureSelect.value;
    const beatsPerMeasure = parseInt(timeSignature.split('/')[0], 10);
    const playlist = [];
    let currentBeat = 0;

    // Traverse all song sections in DOM order
    const sectionDivs = document.querySelectorAll('#song-container .song-section');
    sectionDivs.forEach(sectionDiv => {
        // Play lyrics chords in order
        sectionDiv.querySelectorAll('.lyrics-editor .char[data-chord]').forEach(charSpan => {
            let beats = charSpan.dataset.beats ? parseInt(charSpan.dataset.beats, 10) : 4;
            beats = Math.max(1, Math.min(beats, 8));
            const measure = Math.floor(currentBeat / beatsPerMeasure);
            const beat = currentBeat % beatsPerMeasure;
            let duration;
            if (beats === beatsPerMeasure) {
                duration = '1m';
            } else if (beats === beatsPerMeasure / 2) {
                duration = '2n';
            } else if (beats === beatsPerMeasure / 4) {
                duration = '4n';
            } else {
                duration = `${beats} * 4n`;
            }
            playlist.push({
                time: `${measure}:${beat}:0`,
                chordName: charSpan.dataset.chord,
                element: charSpan,
                duration: duration
            });
            currentBeat += beats;
        });
        // Play instrumental chords in order
        sectionDiv.querySelectorAll('.instrumental-cell .char[data-chord]').forEach(charSpan => {
            let beats = charSpan.dataset.beats ? parseInt(charSpan.dataset.beats, 10) : 4;
            beats = Math.max(1, Math.min(beats, 8));
            const measure = Math.floor(currentBeat / beatsPerMeasure);
            const beat = currentBeat % beatsPerMeasure;
            let duration;
            if (beats === beatsPerMeasure) {
                duration = '1m';
            } else if (beats === beatsPerMeasure / 2) {
                duration = '2n';
            } else if (beats === beatsPerMeasure / 4) {
                duration = '4n';
            } else {
                duration = `${beats} * 4n`;
            }
            playlist.push({
                time: `${measure}:${beat}:0`,
                chordName: charSpan.dataset.chord,
                element: charSpan,
                duration: duration
            });
            currentBeat += beats;
        });
    });

    // Convert beat count to measures for looping and transport
    const totalMeasures = Math.ceil(currentBeat / beatsPerMeasure);
    if (playlist.length === 0) return;

    chordPlaybackPart = new Tone.Part((time, value) => {
        const notes = getNotesFromVoicing(value.chordName);
        console.log('Playback:', value.chordName, notes);
        if (currentInstrument && !isInstrumentLoading && notes.length > 0) {
            currentInstrument.triggerAttackRelease(notes, value.duration, time);
        } else {
            console.warn('Instrument not ready or no notes for', value.chordName);
        }
        Tone.Draw.schedule(() => {
            document.querySelectorAll('.char[data-chord].playing').forEach(el => el.classList.remove('playing'));
            value.element.classList.add('playing');
        }, time);
    }, playlist).start(0);

    const shouldLoop = loopCheckbox.checked;
    chordPlaybackPart.loop = shouldLoop;
    if(shouldLoop){
        chordPlaybackPart.loopEnd = `${totalMeasures}m`;
    } else {
        Tone.Transport.scheduleOnce(() => {
            stopPlayback();
        }, `${totalMeasures}m`);
    }

    Tone.Transport.bpm.value = parseInt(tempoInput.value, 10);
    Tone.Transport.timeSignature = beatsPerMeasure;
    Tone.Transport.start();

    if (document.getElementById('metronome-click-checkbox').checked) {
        metronomeLoop.start(0);
    }

    playStopBtn.querySelector('i').classList.replace('fa-play', 'fa-stop');
};

// FIXED: Added the missing 'export' keyword
export function previewChord(chordName) {
    // Only play if audio context is already running
    if (Tone.context.state === 'running' && currentInstrument && !isInstrumentLoading) {
        const notes = getNotesFromVoicing(chordName);
        if (notes.length > 0) {
            currentInstrument.triggerAttackRelease(notes, '1n');
        }
    }
}

// Add this to audio.js exports:
export const playChordWithDuration = (chordName, duration) => {
    // Only play if audio context is already running
    if (Tone.context.state === 'running' && currentInstrument && !isInstrumentLoading) {
        const notes = getNotesFromVoicing(chordName);
        if (notes.length > 0) {
            currentInstrument.triggerAttackRelease(notes, duration);
        }
    }
};