/**
 * PT Piano - SoundFont Engine (WebAudioFont)
 * Loads and plays instruments from WebAudioFont library
 */
(function() {
    'use strict';

    // Key-to-MIDI mapping for PT Piano keyboard
    // First octave starts at C4 (MIDI 60), second at C5 (MIDI 72)
    const KEY_MIDI_MAP = {
        'a': 60,  // C4
        'w': 61,  // C#4
        's': 62,  // D4
        'e': 63,  // D#4
        'd': 64,  // E4
        'f': 65,  // F4
        't': 66,  // F#4
        'g': 67,  // G4
        'y': 68,  // G#4
        'h': 69,  // A4
        'u': 70,  // A#4
        'j': 71,  // B4
        'k': 72,  // C5
        'o': 73,  // C#5
        'l': 74,  // D5
        'p': 75,  // D#5
        'z': 76,  // E5
        'x': 77,  // F5
        '4': 78,  // F#5
        'c': 79,  // G5
        '5': 80,  // G#5
        'v': 81,  // A5
        '6': 82,  // A#5
        'b': 83,  // B5
        'n': 84,  // C6
        '9': 85,  // C#6
        'm': 86,  // D6
        '0': 87,  // D#6
        ',': 88,  // E6
        '.': 89,  // F6
        '-': 90,  // F#6
        '/': 91,  // G6
        '=': 92,  // G#6
        ';': 93,  // A6
        '[': 94,  // A#6
        '\'': 95, // B6
        ']': 96,  // C7
        '1': 97,  // C#7
        '2': 98,  // D7
        '3': 99,  // D#7
        '8': 100  // E7
    };

    // WebAudioFont instrument catalog
    // Format: GM program number → { name, variable, url }
    const INSTRUMENT_CATALOG = {
        // Piano & Keys
        0:   { name: 'Acoustic Grand Piano',  variable: '_tone_0000_FluidR3_GM_sf2_file',  url: 'https://surikov.github.io/webaudiofontdata/sound/0000_FluidR3_GM_sf2_file.js' },
        1:   { name: 'Bright Acoustic Piano',  variable: '_tone_0010_FluidR3_GM_sf2_file',  url: 'https://surikov.github.io/webaudiofontdata/sound/0010_FluidR3_GM_sf2_file.js' },
        2:   { name: 'Electric Grand Piano',   variable: '_tone_0020_FluidR3_GM_sf2_file',  url: 'https://surikov.github.io/webaudiofontdata/sound/0020_FluidR3_GM_sf2_file.js' },
        4:   { name: 'Electric Piano 1',       variable: '_tone_0040_FluidR3_GM_sf2_file',  url: 'https://surikov.github.io/webaudiofontdata/sound/0040_FluidR3_GM_sf2_file.js' },
        5:   { name: 'Electric Piano 2',       variable: '_tone_0050_FluidR3_GM_sf2_file',  url: 'https://surikov.github.io/webaudiofontdata/sound/0050_FluidR3_GM_sf2_file.js' },
        6:   { name: 'Harpsichord',            variable: '_tone_0060_FluidR3_GM_sf2_file',  url: 'https://surikov.github.io/webaudiofontdata/sound/0060_FluidR3_GM_sf2_file.js' },
        7:   { name: 'Clavinet',               variable: '_tone_0070_FluidR3_GM_sf2_file',  url: 'https://surikov.github.io/webaudiofontdata/sound/0070_FluidR3_GM_sf2_file.js' },

        // Organ
        16:  { name: 'Drawbar Organ',          variable: '_tone_0160_FluidR3_GM_sf2_file',  url: 'https://surikov.github.io/webaudiofontdata/sound/0160_FluidR3_GM_sf2_file.js' },
        17:  { name: 'Percussive Organ',       variable: '_tone_0170_FluidR3_GM_sf2_file',  url: 'https://surikov.github.io/webaudiofontdata/sound/0170_FluidR3_GM_sf2_file.js' },
        18:  { name: 'Rock Organ',             variable: '_tone_0180_FluidR3_GM_sf2_file',  url: 'https://surikov.github.io/webaudiofontdata/sound/0180_FluidR3_GM_sf2_file.js' },
        19:  { name: 'Church Organ',           variable: '_tone_0190_FluidR3_GM_sf2_file',  url: 'https://surikov.github.io/webaudiofontdata/sound/0190_FluidR3_GM_sf2_file.js' },

        // Guitar
        24:  { name: 'Acoustic Guitar (Nylon)',variable: '_tone_0240_FluidR3_GM_sf2_file',  url: 'https://surikov.github.io/webaudiofontdata/sound/0240_FluidR3_GM_sf2_file.js' },
        25:  { name: 'Acoustic Guitar (Steel)',variable: '_tone_0250_FluidR3_GM_sf2_file',  url: 'https://surikov.github.io/webaudiofontdata/sound/0250_FluidR3_GM_sf2_file.js' },
        26:  { name: 'Electric Guitar (Jazz)', variable: '_tone_0260_FluidR3_GM_sf2_file',  url: 'https://surikov.github.io/webaudiofontdata/sound/0260_FluidR3_GM_sf2_file.js' },
        27:  { name: 'Electric Guitar (Clean)',variable: '_tone_0270_FluidR3_GM_sf2_file',  url: 'https://surikov.github.io/webaudiofontdata/sound/0270_FluidR3_GM_sf2_file.js' },
        30:  { name: 'Distortion Guitar',      variable: '_tone_0300_FluidR3_GM_sf2_file',  url: 'https://surikov.github.io/webaudiofontdata/sound/0300_FluidR3_GM_sf2_file.js' },

        // Bass
        32:  { name: 'Acoustic Bass',          variable: '_tone_0320_FluidR3_GM_sf2_file',  url: 'https://surikov.github.io/webaudiofontdata/sound/0320_FluidR3_GM_sf2_file.js' },
        33:  { name: 'Electric Bass (Finger)', variable: '_tone_0330_FluidR3_GM_sf2_file',  url: 'https://surikov.github.io/webaudiofontdata/sound/0330_FluidR3_GM_sf2_file.js' },
        38:  { name: 'Synth Bass',             variable: '_tone_0380_FluidR3_GM_sf2_file',  url: 'https://surikov.github.io/webaudiofontdata/sound/0380_FluidR3_GM_sf2_file.js' },

        // Strings
        40:  { name: 'Violin',                 variable: '_tone_0400_FluidR3_GM_sf2_file',  url: 'https://surikov.github.io/webaudiofontdata/sound/0400_FluidR3_GM_sf2_file.js' },
        42:  { name: 'Cello',                  variable: '_tone_0420_FluidR3_GM_sf2_file',  url: 'https://surikov.github.io/webaudiofontdata/sound/0420_FluidR3_GM_sf2_file.js' },
        46:  { name: 'Orchestral Harp',        variable: '_tone_0460_FluidR3_GM_sf2_file',  url: 'https://surikov.github.io/webaudiofontdata/sound/0460_FluidR3_GM_sf2_file.js' },
        48:  { name: 'String Ensemble',        variable: '_tone_0480_FluidR3_GM_sf2_file',  url: 'https://surikov.github.io/webaudiofontdata/sound/0480_FluidR3_GM_sf2_file.js' },

        // Brass & Wind
        56:  { name: 'Trumpet',                variable: '_tone_0560_FluidR3_GM_sf2_file',  url: 'https://surikov.github.io/webaudiofontdata/sound/0560_FluidR3_GM_sf2_file.js' },
        57:  { name: 'Trombone',               variable: '_tone_0570_FluidR3_GM_sf2_file',  url: 'https://surikov.github.io/webaudiofontdata/sound/0570_FluidR3_GM_sf2_file.js' },
        60:  { name: 'French Horn',            variable: '_tone_0600_FluidR3_GM_sf2_file',  url: 'https://surikov.github.io/webaudiofontdata/sound/0600_FluidR3_GM_sf2_file.js' },
        65:  { name: 'Alto Saxophone',         variable: '_tone_0650_FluidR3_GM_sf2_file',  url: 'https://surikov.github.io/webaudiofontdata/sound/0650_FluidR3_GM_sf2_file.js' },
        71:  { name: 'Clarinet',               variable: '_tone_0710_FluidR3_GM_sf2_file',  url: 'https://surikov.github.io/webaudiofontdata/sound/0710_FluidR3_GM_sf2_file.js' },
        73:  { name: 'Flute',                  variable: '_tone_0730_FluidR3_GM_sf2_file',  url: 'https://surikov.github.io/webaudiofontdata/sound/0730_FluidR3_GM_sf2_file.js' },
        75:  { name: 'Pan Flute',              variable: '_tone_0750_FluidR3_GM_sf2_file',  url: 'https://surikov.github.io/webaudiofontdata/sound/0750_FluidR3_GM_sf2_file.js' },

        // Synth
        80:  { name: 'Synth Lead (Square)',    variable: '_tone_0800_FluidR3_GM_sf2_file',  url: 'https://surikov.github.io/webaudiofontdata/sound/0800_FluidR3_GM_sf2_file.js' },
        81:  { name: 'Synth Lead (Sawtooth)',  variable: '_tone_0810_FluidR3_GM_sf2_file',  url: 'https://surikov.github.io/webaudiofontdata/sound/0810_FluidR3_GM_sf2_file.js' },
        88:  { name: 'Synth Pad (New Age)',    variable: '_tone_0880_FluidR3_GM_sf2_file',  url: 'https://surikov.github.io/webaudiofontdata/sound/0880_FluidR3_GM_sf2_file.js' },
        95:  { name: 'Synth Pad (Sweep)',      variable: '_tone_0950_FluidR3_GM_sf2_file',  url: 'https://surikov.github.io/webaudiofontdata/sound/0950_FluidR3_GM_sf2_file.js' },

        // Ethnic & World
        104: { name: 'Sitar',                  variable: '_tone_1040_FluidR3_GM_sf2_file',  url: 'https://surikov.github.io/webaudiofontdata/sound/1040_FluidR3_GM_sf2_file.js' },
        105: { name: 'Banjo',                  variable: '_tone_1050_FluidR3_GM_sf2_file',  url: 'https://surikov.github.io/webaudiofontdata/sound/1050_FluidR3_GM_sf2_file.js' },
        108: { name: 'Kalimba',                variable: '_tone_1080_FluidR3_GM_sf2_file',  url: 'https://surikov.github.io/webaudiofontdata/sound/1080_FluidR3_GM_sf2_file.js' },
        111: { name: 'Shanai',                 variable: '_tone_1110_FluidR3_GM_sf2_file',  url: 'https://surikov.github.io/webaudiofontdata/sound/1110_FluidR3_GM_sf2_file.js' }
    };

    const PTPSoundFont = {
        player: null,
        audioContext: null,
        currentInstrument: null,
        currentPreset: null,
        active: false,
        loading: false,
        loadedInstruments: {},

        /**
         * Initialize with the shared AudioContext from piano.sound.js
         */
        init: function(audioContext) {
            this.audioContext = audioContext;

            if (typeof WebAudioFontPlayer === 'undefined') {
                console.warn('WebAudioFontPlayer not loaded');
                return;
            }

            this.player = new WebAudioFontPlayer();
            this.bindSelector();
            console.log('PT SoundFont Engine initialized');
        },

        /**
         * Bind the instrument selector dropdown
         */
        bindSelector: function() {
            const select = document.getElementById('ptpianInstrumentSelect');
            if (!select) return;

            select.addEventListener('change', (e) => {
                const programNum = parseInt(e.target.value);
                this.loadInstrument(programNum);
            });
        },

        /**
         * Load an instrument by GM program number
         */
        loadInstrument: async function(programNum) {
            const select = document.getElementById('ptpianInstrumentSelect');

            if (isNaN(programNum) || programNum === null) {
                programNum = 0;
            }

            const info = INSTRUMENT_CATALOG[programNum];
            if (!info) {
                console.error('Unknown instrument:', programNum);
                return;
            }

            if (select) select.value = programNum;

            // Show loading state
            this.loading = true;
            if (select) select.style.opacity = '0.6';

            // Check if already loaded
            if (this.loadedInstruments[programNum]) {
                this.currentPreset = this.loadedInstruments[programNum];
                this.currentInstrument = programNum;
                this.active = true;
                this.loading = false;
                if (select) select.style.opacity = '1';
                console.log('Switched to cached instrument:', info.name);
                return;
            }

            try {
                // Load the instrument JS file dynamically
                await this._loadScript(info.url);

                // Get the instrument data from the global variable
                const preset = window[info.variable];
                if (!preset) {
                    throw new Error('Instrument variable not found: ' + info.variable);
                }

                // Decode the audio data
                this.player.loader.decodeAfterLoading(this.audioContext, info.variable);

                // Cache it
                this.loadedInstruments[programNum] = preset;
                this.currentPreset = preset;
                this.currentInstrument = programNum;
                this.active = true;
                this.loading = false;

                if (select) select.style.opacity = '1';
                console.log('Loaded instrument:', info.name);
            } catch (err) {
                console.error('Failed to load instrument, falling back to Acoustic Grand Piano:', err);
                this.loading = false;
                if (select) {
                    select.style.opacity = '1';
                }
                // Fall back to Acoustic Grand Piano (0) if loading fails
                if (programNum !== 0) {
                    this.loadInstrument(0);
                }
            }
        },

        /**
         * Play a note using the loaded SoundFont instrument
         * @param {string} key - The keyboard key (a, w, s, etc.)
         * @param {number} volume - Volume 0.0 to 1.0
         * @param {AnalyserNode} analyser - For equalizer visualization
         * @returns {object|null} - The envelope for stopping the note
         */
        playNote: function(key, volume, analyser) {
            if (!this.active || !this.player || !this.currentPreset) return null;

            const midiNote = KEY_MIDI_MAP[key];
            if (midiNote === undefined) return null;

            // Create a gain node for volume control
            const gainNode = this.audioContext.createGain();
            gainNode.gain.value = parseFloat(volume) || 0.5;

            // Connect through reverb if available, otherwise direct
            if (window.ptpReverb) {
                window.ptpReverb.applyReverb(gainNode, analyser);
            } else {
                gainNode.connect(analyser);
            }
            analyser.connect(this.audioContext.destination);

            // Play the note using WebAudioFont
            const envelope = this.player.queueWaveTable(
                this.audioContext,
                gainNode,
                this.currentPreset,
                0,              // when: play immediately
                midiNote,       // pitch: MIDI note number
                2,              // duration: 2 seconds (auto-release)
                parseFloat(volume) || 0.5
            );

            return envelope;
        },

        /**
         * Check if SoundFont mode is active
         */
        isActive: function() {
            return this.active && !this.loading && this.currentPreset !== null;
        },

        /**
         * Deactivate SoundFont mode (revert to .wav)
         */
        deactivate: function() {
            this.active = false;
            this.currentPreset = null;
            this.currentInstrument = null;
            console.log('SoundFont deactivated, using WAV files');
        },

        /**
         * Get the current instrument name
         */
        getInstrumentName: function() {
            if (!this.active || this.currentInstrument === null) return 'Default Piano (WAV)';
            const info = INSTRUMENT_CATALOG[this.currentInstrument];
            return info ? info.name : 'Unknown';
        },

        /**
         * Load a script dynamically
         */
        _loadScript: function(url) {
            return new Promise((resolve, reject) => {
                // Check if already loaded
                const existing = document.querySelector(`script[src="${url}"]`);
                if (existing) {
                    resolve();
                    return;
                }

                const script = document.createElement('script');
                script.src = url;
                script.onload = resolve;
                script.onerror = () => reject(new Error('Failed to load: ' + url));
                document.head.appendChild(script);
            });
        }
    };

    // Expose globally
    window.ptpSoundFont = PTPSoundFont;

})();
