import { Injectable, signal } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class AudioEngineService {
  public isListening = signal<boolean>(false);
  public wordsDetected = signal<number>(0);
  public linesDetected = signal<number>(0);
  public energyLevel = signal<number>(0); // For visual feedback
  public searchTranscript = signal<string>('');
  public isSearching = signal<boolean>(false);
  public sensitivity = signal<number>(75); // Default sensitivity (50-100)
  
  public clearSearchTranscript() {
    this.searchTranscript.set('');
  }
  
  private audioContext: AudioContext | null = null;
  private analyser: AnalyserNode | null = null;
  private stream: MediaStream | null = null;
  private animationFrame: number | null = null;
  private recognition: any = null;

  // Detection logic state
  private isSpeaking: boolean = false;
  private lastSilenceTime: number = Date.now();
  private lastWordTime: number = 0;
  
  // Constants for tuning - Optimized for close proximity (singer/guitarist)
  private readonly SILENCE_GAP = 100; // ms
  private readonly LINE_SILENCE_GAP = 600; // ms
  private readonly COOLDOWN = 1000; // ms
  private peakEnergy: number = 0;
  private lineStarted: boolean = false;

  constructor() {
    this.initSpeechRecognition();
  }

  private initSpeechRecognition() {
    const SpeechRecognition = (window as any).SpeechRecognition || (window as any).webkitSpeechRecognition;
    if (SpeechRecognition) {
      this.recognition = new SpeechRecognition();
      this.recognition.continuous = false; // Stop after one phrase for search
      this.recognition.interimResults = true;
      this.recognition.lang = 'it-IT';

      this.recognition.onresult = (event: any) => {
        const text = event.results[0][0].transcript;
        this.searchTranscript.set(text);
      };

      this.recognition.onend = () => {
        this.isSearching.set(false);
      };

      this.recognition.onerror = (err: any) => {
        console.error('Search recognition error:', err);
        this.isSearching.set(false);
      };
    }
  }

  startSearchRecognition() {
    if (!this.recognition) {
      alert('Il riconoscimento vocale non è supportato in questo browser.');
      return;
    }
    this.searchTranscript.set('');
    this.isSearching.set(true);
    try {
      this.recognition.start();
    } catch (e) {
      console.warn('Recognition already started', e);
    }
  }

  stopSearchRecognition() {
    this.recognition?.stop();
    this.isSearching.set(false);
  }

  async startListening() {
    if (this.isListening()) return;

    try {
      this.stream = await navigator.mediaDevices.getUserMedia({ 
        audio: {
          echoCancellation: true,
          noiseSuppression: true,
          autoGainControl: false // Prevents boosting background noise during silence
        } 
      });
      this.audioContext = new AudioContext();
      const source = this.audioContext.createMediaStreamSource(this.stream);
      this.analyser = this.audioContext.createAnalyser();
      this.analyser.fftSize = 512;
      
      source.connect(this.analyser);
      this.isListening.set(true);
      this.processAudio();
    } catch (err) {
      console.error('Error accessing microphone', err);
      alert('Errore microfono: assicurati di usare HTTPS e di aver dato i permessi.');
    }
  }

  stopListening() {
    if (this.animationFrame) cancelAnimationFrame(this.animationFrame);
    this.stream?.getTracks().forEach(track => track.stop());
    this.audioContext?.close();
    this.isListening.set(false);
    this.energyLevel.set(0);
  }

  private processAudio() {
    if (!this.analyser) return;

    const bufferLength = this.analyser.frequencyBinCount;
    const dataArray = new Uint8Array(bufferLength);
    
    const analyze = () => {
      this.analyser!.getByteFrequencyData(dataArray);
      
      // Calculate average energy (volume)
      let sum = 0;
      for (let i = 0; i < bufferLength; i++) {
        sum += dataArray[i];
      }
      const avgEnergy = sum / bufferLength;
      this.energyLevel.set(avgEnergy);

      const now = Date.now();
      // Balanced mapping: 0% -> 220 (very quiet), 100% -> 20 (very sensitive)
      const currentThreshold = 220 - (this.sensitivity() * 2.0); 

      if (avgEnergy > currentThreshold) {
        if (avgEnergy > this.peakEnergy) {
          this.peakEnergy = avgEnergy;
        }

        if (!this.isSpeaking) {
          this.isSpeaking = true;
          this.peakEnergy = avgEnergy; 
          this.lastSilenceTime = now;
        }

        // Se siamo in "speaking" e sentiamo un calo significativo rispetto al picco recente (almeno 30% di calo)
        // Questo permette di avanzare anche se c'è rumore di fondo sopra la soglia base.
        const dropRatio = (this.peakEnergy - avgEnergy) / this.peakEnergy;
        if (this.isSpeaking && dropRatio > 0.35 && this.peakEnergy > currentThreshold * 1.2) {
          if (now - this.lastWordTime > this.COOLDOWN) {
            this.linesDetected.update(v => v + 1);
            this.lastWordTime = now;
            this.peakEnergy = avgEnergy; // Reset peak
            this.isSpeaking = false; 
            console.log('Line advanced - relative drop detected', { dropRatio, avgEnergy, peak: this.peakEnergy });
          }
        }
        
        this.lastSilenceTime = now;
      } else {
        // Sotto soglia (silenzio per il sistema)
        if (this.isSpeaking && (now - this.lastSilenceTime > 200)) {
          if (now - this.lastWordTime > this.COOLDOWN) {
            this.linesDetected.update(v => v + 1);
            this.lastWordTime = now;
            console.log('Line advanced - silence detected');
          }
          this.isSpeaking = false;
          this.peakEnergy = 0;
        }
      }

      this.animationFrame = requestAnimationFrame(analyze);
    };

    analyze();
  }

  resetWordCount() {
    this.wordsDetected.set(0);
    this.linesDetected.set(0);
    this.lineStarted = false;
  }
}
