import { useEffect, useRef, useState } from 'react';
import Jensen, { BluetoothDevice } from '..';
import './index.css';
import { Logger } from './Logger'

export function Home() {
  const [dsn, setDsn] = useState<string|null>(null);
  const [files, setFiles] = useState<Jensen.FileInfo[]>([]);
  const [devices, setDevices] = useState<Jensen.BluetoothDevice[]>([]);
  const [greeting, setGreeting] = useState<string|null>(null);
  const [waveformData, setWaveformData] = useState<number[]>([]);
  const [jensen, setJensen] = useState<Jensen|null>(null);
  const [sourceBuffer, setSourceBuffer] = useState<SourceBuffer|null>(null);

  const getFilePart = () => {
    const file = files[4];
    const secondsLength = Math.ceil(file.length / file.duration) * 1000;
    console.time('!!!time');
    jensen.getFilePart(file.name, secondsLength * 600, (res) => {
      if (res instanceof Uint8Array) {
        console.timeEnd('!!!time');
      }
    });
  };

  let bluetoothDevices: BluetoothDevice[] = [];
  const bluetoothScan  = async () => {
    setDevices([]);
    setGreeting('scan started at: ' + new Date().toLocaleString());
    let devices = await jensen.scanDevices();
    // console.log(devices);
    setDevices(devices);
    setGreeting(null)
  }

  const connect = async () => {
    const usb = (navigator as any).usb;
    let devices = await usb.getDevices();
    for (let i = 0; i < devices.length; i++)
    {
      let dev = devices[i];
      console.log(dev);
      if (dev.vendorId != 0x10d6 && dev.productId != 0x3887) continue;
      await dev.open();
      let inst = new Jensen(Logger, dev);
      await inst.initialize();
      let info = await inst.getDeviceInfo();
      if (info && info.sn)
      {
        setDsn(info.sn);
        setJensen(inst);
        return;
      }
    }
    let dev = await usb.requestDevice({
      filters: [{ vendorId: 0x10d6 }, { vendorId: 0x3887 }]
    });
    if (!dev) return alert('没有找到设备');
    await dev.open();
    let inst = new Jensen(Logger, dev);
    await inst.initialize();
    let info = await inst.getDeviceInfo();
    setDsn(info.sn);
    setJensen(inst);
  }

  const disconnectBTDevice = async () => {
    let r = await jensen.disconnectBTDevice();
    console.log(r);
  }

  const clsBtnConnect = {
    height: '30px',
    padding: '0px 20px',
    position: 'absolute',
    right: '0px',
    top: '3px',
    cursor: 'pointer'
  }

  const clsBleDevice = {
    height: '40px',
    lineHeight: '40px', 
    minWidth: '500px',
    position: 'relative',
    display: 'inline-block'
  }

  const clsBleName = {
    fontSize: '16px',
    fontFamily: 'consolas'
  }

  const doConnectBluetooth = async (mac:string) => {
    // alert(mac);
    let rst = await jensen.connectBTDevice(mac, 10);
    alert('connect: ' + rst.result);
  }

  const getTime = async () => {
    console.log(jensen);
    jensen.dump();
    let time = await jensen.getTime(5);
    alert(JSON.stringify(time));
  }

  const listFiles = async () => {
    let files = await jensen.listFiles();
    setFiles(files)
  }

  const getBluetoothStatus = async () => {
    let info = await jensen.getBluetoothStatus();
    alert(JSON.stringify(info));
  }

  const readFilePartial = async() => {
    if (files.length == 0) return alert('你没有录音文件，或是还没有查询过文件列表');
    let s0 = prompt('请输入需要读取的文件序号，从0开始：', '0');
    let s1 = prompt('请输入开始位置，从0开始：', '0');
    let s2 = prompt('请输入读取字节数量', '32');
    if (s0 && s1 && s2) console.log();
    else return;
    let index = parseInt(s0);
    let offset = parseInt(s1);
    let length = parseInt(s2);
    if (isNaN(index) && isNaN(offset) || isNaN(length)) return;
    if (index >= files.length) return alert('请输入正确的文件序号');
    let file = files[index];
    if (offset < 0 || offset > file.length) return alert('请输入正确的读取开始位置');
    if (length <= 0) return alert('请输入正确的文件读取长度');
    let data = await jensen.readFile(file.name, offset, length);
    console.log(data);
  }

  const updateDeviceTone = async () => {
    let resp = await jensen.requestToneUpdate('826d9bac0b535e7babe02b389327a9f2', 1050688);
    if (resp.code != 0x00) return alert(resp.result);
    
    // 下载文件并完成更新处理
    let xhr = new XMLHttpRequest();
    xhr.open('GET', '/sdfs.bin');
    xhr.setRequestHeader('Content-Type', 'application/octet-stream');
    xhr.responseType = 'arraybuffer';
    xhr.onload = function(e)
    {
      if (this.status != 200) return alert('Http Error: ' + this.status);
      jensen.updateTone(new Uint8Array(this.response), 30).then((info) => {
        alert(JSON.stringify(info));
      });
    }
    xhr.send();
  }

  const updateUAC = async () => {
    // 92e66fd8cfd36f09c83fc61491899307 1024
    let resp = await jensen.requestUACUpdate('92e66fd8cfd36f09c83fc61491899307', 1024);
    if (resp.code != 0x00) return alert(resp.result);
    
    // 下载文件并完成更新处理
    let xhr = new XMLHttpRequest();
    xhr.open('GET', '/UAC.bin');
    xhr.setRequestHeader('Content-Type', 'application/octet-stream');
    xhr.responseType = 'arraybuffer';
    xhr.onload = function(e)
    {
      if (this.status != 200) return alert('Http Error: ' + this.status);
      jensen.updateUAC(new Uint8Array(this.response), 30).then((info) => {
        alert(JSON.stringify(info));
      });
    }
    xhr.send();
  }

  let filename = '';
  let filelength = 0;
  const transferFile = async () => {
    if (files == null || files.length == 0) return alert('请先点击List Files');
    let idx = prompt('请输入需要获取的文件序号(从0开始)：', '0');
    if (idx === undefined || idx === null) return;
    let num = parseInt(idx);
    if (isNaN(num) || num < 0 || num >= files.length) return alert('请输入正确的序号');
    let file = files[num];
    filename = file.name;
    filelength = file.length;

    get_file();
  }

  const get_file = () => {
    jensen.getFile(filename, filelength, function(data) {
      console.log('data', data.length);
    }, function(recvBytes) {
      let percent = Math.floor(recvBytes / filelength * 100);
      console.log('progress', percent);
    });
  }

  const writeSN = async () => {
    let nsn = prompt('请输入新的SN号', '');
    if (nsn && nsn.match(/^HD(H1|1E|P1|PM)\w{9}$/gi))
    {
      let rst = await jensen.writeSerialNumber(nsn);
      alert(rst.result);
    }
  }

  const connectx = async () => {
    const usb = (navigator as any).usb;
    usb.onconnect = (evt: any) => {
      console.log(evt);
    }
    usb.getDevices().then(async (devices: any[]) => {
      for (let i = 0; i < devices.length; i++)
      {
        let dev = devices[i];
        await dev.open();
        let jensen = new Jensen(Logger, dev);
        await jensen.initialize();
        let rst = await jensen.getDeviceInfo();
        console.log(rst);
      }
    });
  }

  // 先创建audio-worker，给到后面使用
  const audioWorker = new Worker(new URL('./audio-worker.js', import.meta.url), { type: 'module' });
  const waveformWorker = new Worker(new URL('./waveform-worker.js', import.meta.url), { type: 'module' });

  waveformWorker.onmessage = (e) => {
    console.log('waveformWorker', e);
  }

  audioWorker.onmessage = (e) => {
    // console.log(e);
    if (e.data.waveformData)
    {
      console.log('waveform', e.data.waveformData);
      // 把e.data.waveformData追加到waveformData的末尾
      // let waveform = [];
      /*
      for (let i = 0; i < e.data.waveformData.length; i++)
      {
        waveform.push(e.data.waveformData[i]);
      }
      */
      // 把waveform追加到waveformData的末尾
      // waveformData.push(...waveform);
      const waveform = e.data.waveformData;
      // console.log(waveformData);

      // 更新波形图waveformCanvas
      const canvas = document.getElementById('waveformCanvas') as HTMLCanvasElement;
      const ctx = canvas.getContext('2d');
      if (ctx)
      {
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        ctx.fillStyle = 'black';
      }
      else
      {
        console.log('no ctx');
        return;
      }

      // 使用waveformData绘制波形图
      const height = canvas.height;
      const width = canvas.width;
      const barWidth = width / waveform.length;
      ctx.lineWidth = 1;
      ctx.lineCap = 'round';
      ctx.strokeStyle = '#0099ff';
      let half = height / 2;
      let x = 0;
      let y = half;
      // ctx.beginPath();
      // ctx.moveTo(x, y);
      for (let i = 0, x = 0; i < waveform.length; i++)
      {
        let v = waveform[i] / 128.0;
        // y = half - v * height / 2 + 2;
        y = (v * height / 2);
        ctx.beginPath();
        ctx.moveTo(x, half - Math.min(y, half));
        ctx.lineTo(x, half + Math.min(y, half));
        ctx.stroke();
        ctx.closePath();
       // 把y反转一下，y = height - y
       // ctx.lineTo(x, height - y);
       x += 3;
      }
      // ctx.stroke();
      // ctx.closePath();
    }
  }

  const mp3: any[] = [];
  let totalBytes = 0;

  const prepareAudio = () => {
    const mediaSource = new MediaSource();
    const audioElement = document.createElement('audio');
    audioElement.autoplay = true;
    audioElement.src = URL.createObjectURL(mediaSource);
    document.body.appendChild(audioElement);

    mediaSource.addEventListener('sourceopen', () => {
      // Create source buffer for MP3
      let sourceBuffer = mediaSource.addSourceBuffer('audio/mpeg');
      setSourceBuffer(sourceBuffer);
      // sourceBuffer.mode = 'sequence';

      alert('sourceopen');
      
      // Feed MP3 data to source buffer
      sourceBuffer.addEventListener('updateend', () => {
        // dequeue();
      });
    });
  }

  const dequeue = () => {
    if (sourceBuffer?.updating == false && mp3.length > 0 && sourceBuffer.buffered.length < 100)
    {
      let clip = mp3.shift();
      sourceBuffer.appendBuffer(clip);
      console.log('appendBuffer', clip.length);
    }
    else
    {
      setTimeout(() => dequeue(), 100);
    }
  }

  const mp3data:any[] = [];

  const test = async () => {
    let idx = prompt('请输入文件序号', '8');
    if (idx === null || idx === undefined) return;
    let file = files[parseInt(idx)];
    if (file === null || file === undefined) return alert('文件不存在');

    jensen.transferFile(file.name, file.length, (data : Uint8Array | 'fail') => {
      if (data instanceof Uint8Array)
      {
        if (sourceBuffer?.updating == false)
        {
          sourceBuffer.appendBuffer(data);
          console.log('directly appendBuffer', data.length);
        }
        else
        {
          console.log('enqueue', data.length);
          mp3.push(data);
          dequeue();
        }
        mp3data.push(data);
        let totalLength = 0;
        for (let i = 0; i < mp3data.length; i++)
        {
          totalLength += mp3data[i].length;
        }
        if (totalLength == file.length)
        {
          let audioData = new Uint8Array(totalLength);
          let offset = 0;
          for (let i = 0; i < mp3data.length; i++)
          {
            audioData.set(mp3data[i], offset);
            offset += mp3data[i].length;
          }
          decodeAudioData(audioData);
        }
      }
    });
  }

  const decodeAudioData = (audioData: Uint8Array) => {
    // 将audioData分成10块，分别发送给audioWorker进行处理
    let clips = 1;
    let blockSize = Math.ceil(audioData.length / clips);
    let audioContext = new AudioContext();
    for (let i = 0; i < clips; i++)
    {
      let block = audioData.buffer.slice(i * blockSize, (i + 1) * blockSize);
      let name = 'block-' + i;
      // audioWorker.postMessage({ data: block, name: name });
      audioContext.decodeAudioData(block).then((buffer) => {
        // console.log('decodeAudioData' + i, buffer);
        waveformWorker.postMessage({ id: name, pcmdata: buffer });
      }).catch((err) => {
        console.log('decodeAudioData' + i, err);
      });
    }
  }

  const transmit = () => {
    let idx = prompt('请输入文件序号', '10');
    if (idx === null || idx === undefined) return;
    let file = files[parseInt(idx)];
    if (file === null || file === undefined) return alert('文件不存在');
    jensen.getFile(file.name, file.length, (data : Uint8Array | 'fail') => {}, (b:number) => {console.log('progress', b)});
    setTimeout(() => {
      jensen.stopReceive();
      console.log('stop receive.......');
      setTimeout(() => {
        jensen.resumeReceive();
        console.log('resume receive.......');
      }, 1500);
    }, 5000);
  }

  return (
    <>
    <div style={{ display: 'flex', flexDirection: 'row', gap: '16px', padding: '16px', alignItems: 'center', flexWrap: 'wrap' }}>
      <button onClick={connect}>{dsn || '连接'}</button>
      <button onClick={listFiles}>文件列表</button>
      <button onClick={prepareAudio}>准备音频</button>
      <button onClick={test}>传输与播放</button>
      <button onClick={transmit}>传输中断测试</button>
      <button onClick={getFilePart}>获取文件</button>
      <button onClick={writeSN}>SN写号</button>
      <button onClick={getTime}>获取时间</button>
      <button onClick={transferFile}>传输文件</button>
      <button onClick={getBluetoothStatus}>蓝牙连接状态</button>
      <button onClick={bluetoothScan}>蓝牙扫描</button>
      <button onClick={disconnectBTDevice}>蓝牙断开</button>
      <button onClick={readFilePartial}>Read File Partial</button>
      <button onClick={updateDeviceTone}>更新提示音</button>
      <button onClick={updateUAC}>更新UAC</button>
    </div>
    <div id="files" style={{ padding: '0px 0px 0px 30px', marginBottom: '20px' }}>
      <h3>Files: </h3>
      <ol style={{ padding: '0px 0px 0px 30px', 'listStyle': 'none' }}>
        { files.map((item, index) => {
          return <li key={item.name}>{index} - {item?.name}, {item?.length} @ {item.duration} - {item.signature}</li>
        })}
      </ol>
    </div>
    <div id="waveform">
      <canvas id="waveformCanvas" width="2000" height="200" style={{ border: '1px solid #ccc' }}></canvas>
    </div>
    <div style={{ padding: '0px 0px 0px 30px', width: '500px' }}>
      <h3>Bluetooth Device List: </h3>
      {
        greeting ? <div>{greeting}</div> : <></>
      }
      {
        devices && devices.length ? (
          devices.map((item, index) => {
            return (
              <div style={clsBleDevice}><span style={clsBleName}>({item.mac}) {item.name}</span><button style={clsBtnConnect} onClick={() => { doConnectBluetooth(item.mac) }}>Connect</button></div>
            );
          })
        ) : (
          <div>no devices...</div>
        )
      }
    </div>
    </>
  );
}
