import * as React from 'react';
import "./RecordingView.scss";
import { ReactElement, useCallback, useEffect, useRef, useState } from "react";
import { ProgressBar } from "./ProgressBar"
import { MdBackspace } from 'react-icons/md';
import { FaCheckCircle } from 'react-icons/fa';
import { IconContext } from "react-icons";
import { Networking } from '../../../Network';
import { Upload } from '../../../../server/SharedMediaTypes';

import { RecordingApi } from '../../../util/RecordingApi';
import { DashUploadUtils } from '../../../../server/DashUploadUtils';

export interface MediaSegment {
    videoChunks: any[],
  endTime: number,
  startTime: number
}

interface IRecordingViewProps {
      setResult: (info: Upload.AccessPathInfo, trackScreen: boolean) => void
      setDuration: (seconds: number) => void
      id: string
}

const MAXTIME = 100000;

export function RecordingView(props: IRecordingViewProps) {

      const [recording, setRecording] = useState(false);
      const recordingTimerRef = useRef<number>(0);
      const [recordingTimer, setRecordingTimer] = useState(0); // unit is 0.01 second
      const [playing, setPlaying] = useState(false);
      const [progress, setProgress] = useState(0);

    const [videos, setVideos] = useState<MediaSegment[]>([]);
    const [orderVideos, setOrderVideos] = useState<boolean>(false);
      const videoRecorder = useRef<MediaRecorder | null>(null);
      const videoElementRef = useRef<HTMLVideoElement | null>(null);

      const [finished, setFinished] = useState<boolean>(false)
      const [trackScreen, setTrackScreen] = useState<boolean>(true)



      const DEFAULT_MEDIA_CONSTRAINTS = {
            video: {
                  width: 1280,
                  height: 720,
            },
            audio: {
                  echoCancellation: true,
                  noiseSuppression: true,
                  sampleRate: 44100
            }
      }


    useEffect(() => {
          
        // console.log('in videos useEffect', finished)

          if (finished) {
              (async () => {
                const inputPaths: string[] = [];
                const videoFiles: File[] = []
                videos.forEach(async (vid, i) => {
                    console.log(vid)
                    const videoFile = new File(vid.videoChunks, `segvideo${i}.mkv`, { type: vid.videoChunks[0].type, lastModified: Date.now() });
                    videoFiles.push(videoFile);
                    
                    const { name } = videoFile;
                    inputPaths.push(name)
                  })
                  
                const serverPaths: string[] = (await Networking.UploadFilesToServer(videoFiles))
                  .map(res => (res.result instanceof Error) ? '' : res.result.accessPaths.agnostic.server)
                
                const result: Upload.AccessPathInfo | Error = await Networking.PostToServer('/concatVideos', serverPaths)
                console.log(result)
                if (!(result instanceof Error)) { // convert this screenshotBox into normal videoBox
                    props.setResult(result, trackScreen)
                } else {
                    alert("video conversion failed");
                }
              
              })();
              
            }


    }, [videos])
  
    
  // make useEffect for progess and log when it fires
  useEffect(() => {
    console.log('progress', progress)
  }, [progress])
  
  useEffect(() => {

    if (finished) {
      setOrderVideos(true);
    }


      }, [finished])

      useEffect(() => {
            // check if the browser supports media devices on first load
            if (!navigator.mediaDevices) {
                  console.log('This browser does not support getUserMedia.')
            }
          // console.log('This device has the correct media devices.')
      }, [])

      useEffect(() => {
            // get access to the video element on every render
            videoElementRef.current = document.getElementById(`video-${props.id}`) as HTMLVideoElement;
      })

      useEffect(() => {
            let interval: any = null;
            if (recording) {
                  interval = setInterval(() => {
                        setRecordingTimer(unit => unit + 1);
                  }, 10);
            } else if (!recording && recordingTimer !== 0) {
                  clearInterval(interval);
            }
            return () => clearInterval(interval);
      }, [recording])

      useEffect(() => {
            setVideoProgressHelper(recordingTimer)
            recordingTimerRef.current = recordingTimer;
      }, [recordingTimer])

      const setVideoProgressHelper = (progress: number) => {
            const newProgress = (progress / MAXTIME) * 100;
            setProgress(newProgress)
      }
      const startShowingStream = async (mediaConstraints = DEFAULT_MEDIA_CONSTRAINTS) => {
            const stream = await navigator.mediaDevices.getUserMedia(mediaConstraints)

            videoElementRef.current!.src = ""
            videoElementRef.current!.srcObject = stream
            videoElementRef.current!.muted = true

            return stream
      }

      const record = async () => {
            const stream = await startShowingStream();
            videoRecorder.current = new MediaRecorder(stream)

            // temporary chunks of video
            let videoChunks: any = []

            videoRecorder.current.ondataavailable = (event: any) => {
                  if (event.data.size > 0) {
                        videoChunks.push(event.data)
                  }
            }

            videoRecorder.current.onstart = (event: any) => {
                  setRecording(true);
                  trackScreen && RecordingApi.Instance.start();
            }

            videoRecorder.current.onstop = () => {
                  // if we have a last portion
                  if (videoChunks.length > 1) {
                        // append the current portion to the video pieces
                        setVideos(videos => [...videos, { videoChunks: videoChunks, endTime: recordingTimerRef.current, startTime: videos?.lastElement()?.endTime || 0 }])
                  }

                  // reset the temporary chunks
                  videoChunks = []
                  setRecording(false);
                  trackScreen && RecordingApi.Instance.pause();
            }

            // recording paused
            videoRecorder.current.onpause = (event: any) => {
                  // append the current portion to the video pieces
                  setVideos(videos => [...videos, { videoChunks: videoChunks, endTime: recordingTimerRef.current, startTime: videos?.lastElement()?.endTime || 0 }])

                  // reset the temporary chunks
                  videoChunks = []
                  setRecording(false);
                  trackScreen && RecordingApi.Instance.pause();
            }

            videoRecorder.current.onresume = async (event: any) => {
                  await startShowingStream();
                  setRecording(true);
                  trackScreen && RecordingApi.Instance.resume();
            }

            videoRecorder.current.start(200)
      }


  const stop = (e: React.MouseEvent) => {
        e.stopPropagation()
        if (videoRecorder.current) {
          setFinished(true);
                  if (videoRecorder.current.state !== "inactive") {
                        videoRecorder.current.stop();
                        // recorder.current.stream.getTracks().forEach((track: any) => track.stop())
                  }
            }
      }

      const pause = (e: React.MouseEvent) => {
        e.stopPropagation()
            if (videoRecorder.current) {
                  if (videoRecorder.current.state === "recording") {
                    videoRecorder.current.stop();
                  }
            }
      }

      const startOrResume =  (e: React.MouseEvent) => {
        e.stopPropagation()
            if (!videoRecorder.current || videoRecorder.current.state === "inactive") {
                  record();
            } else if (videoRecorder.current.state === "paused") {
              videoRecorder.current.start();
            }
      }

      const clearPrevious = () => {
            const numVideos = videos.length
            setRecordingTimer(numVideos == 1 ? 0 : videos[numVideos - 2].endTime)
            setVideoProgressHelper(numVideos == 1 ? 0 : videos[numVideos - 2].endTime)
            setVideos(videos.filter((_, idx) => idx !== numVideos - 1));
      }

      const handleOnTimeUpdate = () => {
            if (playing) {
                  setVideoProgressHelper(videoElementRef.current!.currentTime)
            }
      };

      const millisecondToMinuteSecond = (milliseconds: number) => {
            const toTwoDigit = (digit: number) => {
                  return String(digit).length == 1 ? "0" + digit : digit
            }
            const minutes = Math.floor((milliseconds % (1000 * 60 * 60)) / (1000 * 60));
            const seconds = Math.floor((milliseconds % (1000 * 60)) / 1000);
            return toTwoDigit(minutes) + " : " + toTwoDigit(seconds);
      }

      return (
            <div className="recording-container">
                  <div className="video-wrapper">
                        <video id={`video-${props.id}`}
                              autoPlay
                              muted
                              onTimeUpdate={handleOnTimeUpdate}
                        />
                        <div className="recording-sign">
                              <span className="dot" />
                              <p className="timer">{millisecondToMinuteSecond(recordingTimer * 10)}</p>
                        </div>
                        <div className="controls">

                              <div className="controls-inner-container">
                                    <div className="record-button-wrapper">
                                          {recording ?
                                                <button className="stop-button" onClick={pause} /> :
                                                <button className="record-button" onClick={startOrResume} />
                                          }
                                    </div>

                                    {!recording && (videos.length > 0 ?

                                          <div className="options-wrapper video-edit-wrapper">
                                                {/* <IconContext.Provider value={{ color: "grey", className: "video-edit-buttons" }}>
                                                      <MdBackspace onClick={clearPrevious} />
                                                </IconContext.Provider> */}
                                                <IconContext.Provider value={{ color: "#cc1c08", className: "video-edit-buttons" }}>
                                                      <FaCheckCircle onClick={stop} />
                                                </IconContext.Provider>
                                          </div>

                                          : <div className="options-wrapper track-screen-wrapper">
                                                <label className="track-screen">
                                                      <input type="checkbox" checked={trackScreen} onChange={(e) => { setTrackScreen(e.target.checked) }} />
                                                      <span className="checkmark"></span>
                                                      Track Screen
                                                </label>
                              </div>)}

                      </div>
                              
                  </div>
                  
                                         <ProgressBar
              videos={videos}
              setVideos={setVideos}
              orderVideos={orderVideos}
                              // playSegment={playSegment}
                              />
                  </div>
            </div>)
}