// recorder.js

class PianoRecorder {
    constructor() {
        this.isRecording = false;
        this.recordedNotes = [];
        this.recordingStartTime = null;
		
        this.exportTempo = 120;       // Current tempo for playback/export (BPM)
        this.recordingTempo = 120;    // Tempo at which the recording was made
        this.timeScale = 0.5;         // Compress or stretch note timing for MIDI export
    }
	
	setTempo(bpm) {
		this.exportTempo = bpm;
	}


    startRecording() {		
        this.isRecording = true;
        this.recordedNotes = [];
        this.recordingStartTime = performance.now();
        // Save the tempo at the moment recording starts
        this.recordingTempo = this.exportTempo;
    }

    stopRecording() {
        this.isRecording = false;
    }

    recordNote(key, note) {
        if (!this.isRecording) return;
        const currentTime = performance.now();
        this.recordedNotes.push({
            key,
            note,
            time: currentTime - this.recordingStartTime,
        });
    }
	
    playRecording(playTuneFn, onComplete) {
		
	  if (!this.recordedNotes.length) return;
	  
	  // Use the tempo from when the recording was made as the reference
	  const tempoScale = this.recordingTempo / this.exportTempo;
	  this.playingNotes = [];

	  this.recordedNotes.forEach(note => {
		const delay = Math.max(note.time * tempoScale, 20);

		const timer = setTimeout(() => {
		  playTuneFn(note.key);
		}, delay);
		this.playingNotes.push(timer);
	  });

	  // Save final timeout to call onComplete
	  const lastNoteTime  = this.recordedNotes[this.recordedNotes.length - 1].time;
	  const totalTime = lastNoteTime * tempoScale;
	  this.playbackTimer = setTimeout(() => {
		this.playingNotes = [];
		this.playbackTimer = null;
		if (onComplete && typeof onComplete === "function") {
			onComplete();
		}
	  }, totalTime + 200); // Add small buffer
	}


	stopPlayback() {
	  if (this.playbackTimer) {
		clearTimeout(this.playbackTimer);
		this.playbackTimer = null;
	  }

	  if (this.playingNotes && this.playingNotes.length) {
		this.playingNotes.forEach(timer => clearTimeout(timer));
		this.playingNotes = [];
	  }
	}
	
	downloadMidi() {
		if (!this.recordedNotes || !this.recordedNotes.length) {
			if (window.PTPiano && window.PTPiano.SaveWarningPopup) {
				window.PTPiano.SaveWarningPopup.open();
			} else {
				alert("No notes recorded yet!");
			}
			return;
		}

		const track = new MidiWriter.Track();

		// === Set Meta Information ===		
		const ppq = 128; // default in MidiWriterJS
		track.setTempo(this.exportTempo);
		track.setTimeSignature(4, 4);
		track.addTrackName("Virtual Piano Track");
		track.addInstrumentName("Acoustic Grand Piano");

		let lastTimestamp = 0;

		this.recordedNotes.forEach(note => {
			const midiNote = this.noteToMidiNumber(note.note); // e.g., 60 for C4
			const timeDiffMs = note.time - lastTimestamp;
			lastTimestamp = note.time;

			// Convert milliseconds to ticks
			//const ticks = Math.round((timeDiffMs / 1000) * (ppq * bpm / 60));
			const ticks = Math.round(((timeDiffMs * this.timeScale) / 1000) * (ppq * this.exportTempo / 60));

			const noteEvent = new MidiWriter.NoteEvent({
				pitch: [midiNote],
				duration: 'T' + ticks, // Custom tick-based duration
				wait: 'T' + ticks      // Custom tick-based delta time
			});

			track.addEvent(noteEvent);
		});

		const writer = new MidiWriter.Writer(track);
		const midiData = writer.buildFile(); // Uint8Array

		const blob = new Blob([midiData], { type: 'audio/midi' });
		const url = URL.createObjectURL(blob);

		const a = document.createElement('a');
		a.href = url;
		a.download = 'piano-recording.mid';
		a.click();
		URL.revokeObjectURL(url);
	}
	
	noteToMidiNumber(note) {
		const noteMap = {
			'C': 0, 'C#': 1, 'D': 2, 'D#': 3, 'E': 4,
			'F': 5, 'F#': 6, 'G': 7, 'G#': 8,
			'A': 9, 'A#': 10, 'B': 11
		};
		const baseMidi = 60; // C4
		return this.midiNumberToPitch(baseMidi + (noteMap[note] ?? 0));
	}

	midiNumberToPitch(midiNumber) {
		const noteNames = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'];
		const note = noteNames[midiNumber % 12];
		const octave = Math.floor(midiNumber / 12) - 1;
		return note + octave;
	}
    
}

const pianoRecorder = new PianoRecorder();
window.pianoRecorder = pianoRecorder; // optional global
