import { Injectable } from '@angular/core';
import { Capacitor } from '@capacitor/core';
import { Filesystem, Directory } from '@capacitor/filesystem';

@Injectable({
  providedIn: 'root'
})
export class AudioService {
  private audioContext!: AudioContext;
  private mediaRecorder!: MediaRecorder;
  private audioChunks: Blob[] = [];
  private audioAnalyser!: AnalyserNode;
  private microphone!: MediaStreamAudioSourceNode;
  private scriptProcessor!: ScriptProcessorNode;
  private volumeCallback!: (volume: number) => void;
  private isRecording = false;

  constructor() {}

  initAudioContext() {
    if (!this.audioContext) {
      this.audioContext = new (window.AudioContext || (window as any).webkitAudioContext)();
    }
  }

  async startRecording(volumeCallback: (volume: number) => void): Promise<void> {
    this.volumeCallback = volumeCallback;
    this.audioChunks = [];
    
    try {
      const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
      this.mediaRecorder = new MediaRecorder(stream);
      
      // 设置音频分析
      this.setupAudioAnalysis(stream);
      
      this.mediaRecorder.ondataavailable = (event) => {
        this.audioChunks.push(event.data);
      };
      
      this.mediaRecorder.start(100); // 每100ms收集一次数据
      this.isRecording = true;
    } catch (error) {
      console.error('无法访问麦克风:', error);
      throw error;
    }
  }

  private setupAudioAnalysis(stream: MediaStream) {
    this.microphone = this.audioContext.createMediaStreamSource(stream);
    this.audioAnalyser = this.audioContext.createAnalyser();
    this.audioAnalyser.fftSize = 256;
    
    this.scriptProcessor = this.audioContext.createScriptProcessor(2048, 1, 1);
    
    this.microphone.connect(this.audioAnalyser);
    this.audioAnalyser.connect(this.scriptProcessor);
    this.scriptProcessor.connect(this.audioContext.destination);
    
    const that = this;
    this.scriptProcessor.onaudioprocess = function() {
      if (!that.isRecording) return;
      
      const array = new Uint8Array(that.audioAnalyser.frequencyBinCount);
      that.audioAnalyser.getByteFrequencyData(array);
      
      let values = 0;
      const length = array.length;
      
      for (let i = 0; i < length; i++) {
        values += array[i];
      }
      
      const average = values / length;
      that.volumeCallback(average);
    };
  }

  async stopRecording(): Promise<Blob> {
    return new Promise((resolve) => {
      this.mediaRecorder.onstop = () => {
        const audioBlob = new Blob(this.audioChunks, { type: 'audio/wav' });
        resolve(audioBlob);
      };
      
      this.mediaRecorder.stop();
      this.cleanupAudioNodes();
      this.isRecording = false;
    });
  }

  getRecordedChunks(): Blob[] {
    return this.audioChunks;
  }

  analyzeAudio(audioChunks: Blob[], callback: (dataArray: Uint8Array) => void) {
    const audioBlob = new Blob(audioChunks, { type: 'audio/wav' });
    const fileReader = new FileReader();
    
    fileReader.onload = () => {
      const arrayBuffer = fileReader.result as ArrayBuffer;
      this.audioContext.decodeAudioData(arrayBuffer).then((audioBuffer) => {
        const offlineContext = new OfflineAudioContext(
          audioBuffer.numberOfChannels,
          audioBuffer.length,
          audioBuffer.sampleRate
        );
        
        const source = offlineContext.createBufferSource();
        source.buffer = audioBuffer;
        
        const analyser = offlineContext.createAnalyser();
        analyser.fftSize = 2048;
        
        source.connect(analyser);
        analyser.connect(offlineContext.destination);
        
        source.start(0);
        
        offlineContext.startRendering().then(() => {
          const bufferLength = analyser.frequencyBinCount;
          const dataArray = new Uint8Array(bufferLength);
          analyser.getByteTimeDomainData(dataArray);
          callback(dataArray);
        });
      });
    };
    
    fileReader.readAsArrayBuffer(audioBlob);
  }

  private cleanupAudioNodes() {
    if (this.scriptProcessor) {
      this.scriptProcessor.disconnect();
      this.scriptProcessor.onaudioprocess = null;
    }
    
    if (this.microphone) {
      this.microphone.disconnect();
    }
    
    if (this.mediaRecorder && this.mediaRecorder.stream) {
      this.mediaRecorder.stream.getTracks().forEach(track => track.stop());
    }
  }
}