import React, { useState, useEffect, useContext, useRef } from 'react';
import fxauto from '../function/fxauto';
import { Flex, Radio } from 'antd';

const baseStyle: React.CSSProperties = {
    width: '25%',
    height: 54,
  };
interface Config {
    SRATE: number;
    fxmin: number;
    fxlow: number;
    fxhigh: number;
    fxmax: number;
}

interface PitchDetectorProps {
    onPitchChange: (value: number | null) => void;
    onBallHistoryChange: (value: number[]) => void
    size: number[];
    config: Config;
    isPlaying: boolean;
}

function map(value: number | null, in_min: number, in_max: number, out_min: number, out_max: number): number {
    if (value === null) {
        value = 0;
    }
    return (value - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}


function PitchDetector({ config, isPlaying, onPitchChange,onBallHistoryChange,size}: PitchDetectorProps) {
    const [pitchValue, setPitchValue] = useState<number | null>(null);
    const [context, setContext] = useState<AudioContext | null>(null);
    const [micsource, setMicsource] = useState<MediaStreamAudioSourceNode | null>(null);
    const [ballY,setBallY] = useState<number>(size[0]);
    const [ballHistory, setBallHistory] = useState<number[]>([]);
    const { SRATE, fxmin, fxlow, fxhigh, fxmax } = config;
    const isPlayingRef = useRef(isPlaying);
    isPlayingRef.current = isPlaying; 


    const addValueToHistory = (value: number) => {
        setBallHistory(prevHistory => [...prevHistory, value]);
      };

    function updateBallPosition(currentPitchValue: number | null) {
        // console.log(currentPitchValue);
        let newBallY;
        // if pitch is 0, then at bottom
        if (currentPitchValue == 0) {
            newBallY = size[0];
        } else {
            newBallY = map(currentPitchValue, fxmin, fxmax, size[0], -1);
        }
        // console.log(newBallY);
        setBallY(newBallY);
        // update ball history with the new ballY value
        addValueToHistory(newBallY);
        
        // remove oldest position
        setBallHistory(prevHistory => {
            if (prevHistory.length * 5 > size[1]-400) {
                return prevHistory.slice(1); 
            }
            return prevHistory;
        });
    }
    
    useEffect(() => {
        // console.log(ballHistory);
        onBallHistoryChange(ballHistory);
    }, [ballHistory]);

    
    useEffect(() => {
        // console.log(isPlaying)
        if(!isPlaying) {
            return; // Exit the effect if not playing
        }
        if (!context) {
            
            navigator.mediaDevices.getUserMedia({ audio: true })
                .then(stream => {
                    const fxcalc = new fxauto(fxmin, fxlow, fxhigh, fxmax, SRATE);
                    const audioContext = new window.AudioContext();
                    const source = audioContext.createMediaStreamSource(stream);
                    const capturenode = audioContext.createScriptProcessor(2048, 1, 1);
                    console.log(isPlaying)
                    capturenode.onaudioprocess = function(e) {
                        const buf = e.inputBuffer.getChannelData(0);
                        const fxest = fxcalc.CalculateFx(buf, buf.length);
                        if (fxest.en > 0) { 
                            if((isPlayingRef.current)) {
                                // console.log(isPlayingRef.current)
                                setPitchValue(fxest.fx);
                                onPitchChange(fxest.fx); // 通知父组件
                                updateBallPosition(fxest.fx);
                            }
                            
                        }   
                    };


                    source.connect(capturenode);
                    capturenode.connect(audioContext.destination);

                    setContext(audioContext);
                    setMicsource(source);
                })
                .catch(err => {
                    alert('Error accessing the microphone: ' + err.message);
                });
        }
    }, [isPlaying, context, onPitchChange, onBallHistoryChange]);

    return (
            <div>
                <Flex vertical >
                    <h1>Pitch Detector </h1>
                    <p>Detected Pitch: {pitchValue ? pitchValue.toFixed(2) + " Hz" : "N/A"}</p>
                </Flex>
                
            </div>
    );

}

export default PitchDetector;