import Taro from "@tarojs/taro";
import { ECharacterAISTATUS } from '@/types/index'
let audioCtx:Taro.WebAudioContext | AudioContext;
if (process.env.TARO_ENV === 'h5') {
  audioCtx = new AudioContext()
}else {
  audioCtx = Taro.createWebAudioContext()
}
let source: AudioBufferSourceNode;
let enablePlay = true; // 用于中断流式播放
let chunks: ArrayBuffer[] = []; // 流式播放　chunks
let playStatusChangedCallback:(status: ECharacterAISTATUS)=>void;
let requestTask = null;
export const useAudioPlayer = () => {
  const WAV_HEADER_LENGTH = 44
  let totalLength = WAV_HEADER_LENGTH;

  let playing = false
  let wavHeader: ArrayBuffer;

  const changeStatus = (status: ECharacterAISTATUS)=> {
    playStatusChangedCallback && playStatusChangedCallback(status)
  }
  
  const setFistChunk = (chunk: ArrayBuffer, _requestTask?: any) => {
    if(_requestTask){
      requestTask = _requestTask  
    }
    enablePlay = true;
    changeStatus(ECharacterAISTATUS.THINKING)
    emptyQuene();
    wavHeader = chunk.slice(0, WAV_HEADER_LENGTH);
    const firstChunkData = chunk.slice(WAV_HEADER_LENGTH);
    pushChunk2Quene(firstChunkData)
  }
  const pushChunk2Quene = (chunk: ArrayBuffer) => {
    chunks.push(chunk);
    totalLength += chunk.byteLength;
  }

  const emptyQuene = () => {
    chunks = []
    totalLength = WAV_HEADER_LENGTH;
  }

  const playChunk = () => {
    if(!enablePlay){
      emptyQuene();
      return ;
    }
    if(playing){
      return;
    }
    if (!chunks.length) {
      playing = false
      return;
    }
    playing = true;
    changeStatus(ECharacterAISTATUS.RESPONDING)
    let tmp = [...chunks]

    const _chunk = combineArrayBuffers(tmp, totalLength)
    const partChunks = combineHeaderAndChunk(wavHeader, _chunk)
    emptyQuene();
    //@ts-ignore
    audioCtx.decodeAudioData(partChunks, (decodedBuffer: AudioBuffer) => {
      source = audioCtx.createBufferSource();
      //@ts-ignore
      source.connect(audioCtx.destination);
      source.buffer = decodedBuffer;
      console.log('play start')
      source.onended = () => {
        console.log('play end')
        playing = false
        changeStatus(ECharacterAISTATUS.IDLE)
        playChunk()
      };
      source.start(0);
    }, (err:any) => {
      console.log(err)
      playing = false;
    })
  }

  const stopPlayChunk = () => {
    // 如果有请求任务取消
    if(requestTask){
      //@ts-ignore
      requestTask?.abort?.()
      //@ts-ignore
      requestTask?.offChunkReceived?.()
    }
    emptyQuene();
    source && source.stop();
    enablePlay = false;
    changeStatus(ECharacterAISTATUS.IDLE)
    // console.log('stop play chunk')
  }

  const onPlayerStatusChanged = (callback: (status: number)=>void) => {
    playStatusChangedCallback = callback
  }

  return {
    pushChunk2Quene,
    playChunk,
    stopPlayChunk,
    setFistChunk,
    onPlayerStatusChanged,
  }
}

function combineArrayBuffers(arrays: ArrayBuffer[], totalLength: number): ArrayBuffer {
  const result = new Uint8Array(totalLength);
  let offset = 0;

  for (let i = 0; i < arrays.length; i++) {
    const array = new Uint8Array(arrays[i]);
    result.set(array, offset);
    offset += array.length;
  }

  return result.buffer;
}


function combineHeaderAndChunk(header:ArrayBuffer, chunk:ArrayBuffer) {
  // Create a new ArrayBuffer to hold both the header and the chunk
  const combinedBuffer = new ArrayBuffer(header.byteLength + chunk.byteLength);

  // Create a Uint8Array view of the combined buffer
  const combinedView = new Uint8Array(combinedBuffer);

  // Copy the header into the combined buffer
  combinedView.set(new Uint8Array(header), 0);

  // Copy the chunk data after the header
  combinedView.set(new Uint8Array(chunk), header.byteLength);

  return combinedBuffer;
}

// // Usage example
// let storedHeader = null;
// let isFirstChunk = true;

// ws.onmessage = function(event) {
//   if (isFirstChunk) {
//       // Assume the first 44 bytes are the header
//       storedHeader = event.data.slice(0, 44);
//       // const headerInfo = parseWavHeader(storedHeader);
//       // console.log("WAV Header Info:", headerInfo);

//       // Handle the rest of the first chunk as audio data
//       const firstChunkData = event.data.slice(44);
//       const combinedData = combineHeaderAndChunk(storedHeader, firstChunkData);
//       processAudioData(combinedData);

//       isFirstChunk = false;
//   } else {
//       // For subsequent chunks, combine with the stored header
//       const combinedData = combineHeaderAndChunk(storedHeader, event.data);
//       processAudioData(combinedData);
//   }
// };

// function processAudioData(audioData) {
//   // Here you would typically send the data to the Web Audio API
//   // For example:
//   // audioContext.decodeAudioData(audioData)
//   //     .then(decodedData => {
//   //         // Use the decoded audio data
//   //     })
//   //     .catch(error => console.error("Error decoding audio data:", error));
// }
