import { makeStyles, Typography } from '@material-ui/core'
import { useState,useEffect,useCallback,useRef } from 'react';
import { useSelector } from 'react-redux';
import io from 'socket.io-client';
import Moveable from "react-moveable";
import { OnDrag } from "react-moveable";
import ListItemText from '@mui/material/ListItemText';
import ListItemAvatar from '@mui/material/ListItemAvatar';
import Avatar from '@mui/material/Avatar';
import PhoneIcon from '@mui/icons-material/Phone';
import MinimizeIcon from '@mui/icons-material/Minimize';
import CropLandscapeIcon from '@mui/icons-material/CropLandscape';
import CloseIcon from '@mui/icons-material/Close';
import VideocamIcon from '@mui/icons-material/Videocam';
import VideocamOffIcon from '@mui/icons-material/VideocamOff';
import MicIcon from '@mui/icons-material/Mic';
import MicOffIcon from '@mui/icons-material/MicOff';
import CallEndIcon from '@mui/icons-material/CallEnd';
import Alert from '@mui/material/Alert';

import { getChat } from '../../../redux/chat/selector';
import { getAuthorizationState } from '../../../redux/authorization/selector'; 
import { prodAwsS3,prodBaseURL,prodSocketURL, firstLetter, slicedWord,getTimeBySeconds,playNotification } from '../../../helpers'
import { socketIdChat } from '../../../api-data';

const Peer = require('simple-peer')
const socket = io(prodSocketURL)

const useStyles = makeStyles({
  container: {
    position: 'absolute',
    left: 0,
    top: 0,
    width: '100vw',
    height:'100vh',
    overflow: 'hidden',
    zIndex:100,
    display: 'flex',
    justifyContent: 'center',
    alignItems: 'center',
    alignContent: "center",
    backgroundColor: 'rgba(104, 105, 104, 0.6)',
  },  
  modalCall: {
    background: 'rgb(36, 36, 36)',
    position:'relative',
    display: 'flex',
    flexDirection: 'column',
    justifyContent: 'start',
    alignItems: 'center',
    justifyItems:"center",
    borderRadius: 7,
  },
  rightIcons: {
    display: 'flex',
    justifyContent: 'end',
    alignContent: 'center',
    alignItems: 'center',
    width: '100%',
    position: 'absolute',
    left: 0,
    top: 0,
    zIndex:1
  },
  rightIconWrapper: {
    color: '#ffffff',
    cursor: 'pointer',
    padding:'3px 10px 3px 10px',
  },
  rightIconWrapperClose: {
    color: '#ffffff',
    cursor: 'pointer',
    padding: '3px 10px 3px 10px',
    backgroundColor:'rgb(36, 36, 36)',
    borderTopRightRadius:7,
    '&:hover': {
      backgroundColor:'#f02a2a'
    }
  },
  bottomWrapper: {
    display: 'flex',
    justifyContent: 'center',
    padding: 5,
    position: "absolute",
    left: 0,
    bottom: 0,
    width:'100%'
  },
  bottomItem: {
    display: 'flex',
    flexDirection: 'column',
    justifyContent: 'center',
    alignContent: 'center',
    alignItems: 'center',
    cursor:'pointer', 
    width: 80,
  },
  bottomIcon: {
    cursor:'pointer',
  },
  bottomIconEndAccept: {
    cursor: 'pointer',
    '&:hover': {
      animation: `$shake 1s`,
      animationIterationCount:'infinite', 
    }
  },  
  ringPulsate: {
   backgroundColor:"rgb(80, 80, 80)",
   borderRadius: '50%',
   height: 60,
   width: 60,
   position: 'absolute',
   left: 10,
   top: -8,
   animation: `$pulsate 1.5s ease-out`,
   animationIterationCount: 'infinite',
   opacity: 0,
 },  
  titleIconBottom: {
    color: '#ffffff',
    fontSize: 13,
    paddingTop:7
  },
  myVideo: {
    cursor: 'pointer',
    position: 'absolute',
    top: 0,
    left: 0,
    zIndex: 150,
  },  
  '@keyframes pulsate': {
    '0%': {transform: 'scale(1, 1)', opacity: 0},
    '50%': { opacity: 1},
    '100%': {transform: 'scale(1.2, 1.2)', opacity: 0},
  },
  '@keyframes shake': {
  '0%': { transform: 'rotate(0deg)'},
  '11%': { transform: 'rotate(10deg)'},
  '22%': { transform: 'rotate(20deg)'},
  '33%': { transform: 'rotate(30deg)'},
  '44%': { transform: 'rotate(20deg)'},
  '55%': { transform: 'rotate(10deg)'},
  '66%': { transform: 'rotate(0deg)'},
  '77%': { transform: 'rotate(-10deg)'},
  '88%': { transform: 'rotate(-20deg)'},
  '100%': { transform: 'rotate(-30deg)'},
  },  
})

interface ICallBar {
  callStatus:any,
  setCallStatus: any,
}

const CallBar = ({callStatus,setCallStatus}:ICallBar) => {
  const classes = useStyles()
  const { _id } = useSelector(getAuthorizationState)
  const chat = useSelector(getChat)
  const { socketId, companionId } = chat
  const connectionRef = useRef<any>(null);
  const idAudioIntervalRef = useRef<any>(null);
  const myVideoRef = useRef<any>(null);
  const companionVideoRef = useRef<any>(null);
  const companionAudioRef = useRef<any>(null);
  const [mySocket, setMySocket] = useState<string>('')
  const [mutedMyVideo,setMutedMyVideo] = useState<boolean>(false)
  const [mutedMyAudio,setMutedMyAudio] = useState<boolean>(false)
  const [companionSocket, setCompanionSocket] = useState<string>('')
  const [myStream, setMyStream] = useState<any>(null)
  const [companionSignal, setCompanionSignal] = useState<any>(null)
  const [name, setName] = useState<string>('')
  const [lastName, setLastName] = useState<string>('')
  const [avatarUrl, setAvatarUrl] = useState<string>('')
  const [color, setColor] = useState<string>('')
  const [number, setNumber] = useState<string>('')
  const [callLast, setCallLast] = useState<number>(0)
  const [conversationLast, cetConversationLast] = useState<string>('')
  const [fullScreen, setFullScreen] = useState<boolean>(false)
  const [alert, setAlert] = useState<string>('')
  const [audioHtml, setAudioHtml] = useState<any>(null)

  const handleLeaveCall = useCallback(() => {
    if (callStatus === 'is calling you') {
      socket.emit("answerCall", {
        signal: 'declined',
        to: companionSocket,
      });
    }
    if(connectionRef.current) connectionRef.current.destroy();
    if(idAudioIntervalRef.current) clearInterval(idAudioIntervalRef.current)
    myVideoRef.current.srcObject = null
    companionVideoRef.current.srcObject = null
    companionAudioRef.current.srcObject = null
    if (audioHtml) {
      audioHtml.pause()
      setAudioHtml(null)
    }
    if(myStream) myStream.getTracks().forEach((track:any) => track.stop())
    setMutedMyVideo(false)
    setMutedMyAudio(false)
    setCompanionSocket('')
    setMyStream(null)
    setCompanionSignal(null)
    setName('')
    setLastName('')
    setAvatarUrl('')
    setColor('')
    setNumber('')
    setCallLast(0)
    cetConversationLast('')
    setFullScreen(false)
    setAlert('')
    setCallStatus('')
  }, [setCallStatus, callStatus, companionSocket, audioHtml, myStream])

  const handleHangUp = () =>
    setCallStatus('hanging up...')
  
  const handleConversationLast = (e: any) =>
    cetConversationLast(getTimeBySeconds(e.target.currentTime))
  
  const handleMuteVideo = () => {
    if (myStream&&myStream.getVideoTracks()[0]) {
      setMutedMyVideo(!mutedMyVideo)
      myStream.getVideoTracks()[0].enabled = !myStream.getVideoTracks()[0].enabled
    } else {
      setAlert(`You can not ${mutedMyVideo?'enable':'disable'} Video before stream started`)
    }
  }

  const handleMuteAudio = () => {
    if (myStream&&myStream.getAudioTracks()[0]) {
      setMutedMyAudio(!mutedMyAudio)
      myStream.getAudioTracks()[0].enabled = !myStream.getAudioTracks()[0].enabled
    } else {
      setAlert(`You can not ${mutedMyAudio?'enable':'disable'} Audio before stream started`)
    }
  }
  
  const handleStartCall = useCallback(async () => {
    try {
      setCallStatus('waiting...')
      const mediaDevices: any = navigator.mediaDevices
      const stream = await mediaDevices.getDisplayMedia({
        video: true,
        audio: true
      })
      setMyStream(stream)
      myVideoRef.current.srcObject = stream;
      const peer = new Peer({
        initiator: true,
        trickle: false, 
        stream 
      });
      const audioRing = playNotification(`${prodBaseURL}/calling.mp3`)
      audioRing.loop = true
      setAudioHtml(audioRing)
      idAudioIntervalRef.current = setInterval(() =>
        setCallLast(prevState => prevState + 1), 1000)
      peer.on("signal", (data: any) => {
        setCallStatus('ringing...')
        socket.emit("callTo", {
          to: socketId,
          signalData: data,
          from: mySocket,
          userId: _id,
          companionId,
          peer
        })
      });
      peer.on("stream", (companionStream: any) => {
        companionVideoRef.current.srcObject = companionStream;
        companionAudioRef.current.srcObject = companionStream;
      });
      peer.on('connect', () => {
        setCallStatus('connection')
        setAlert('')
        audioRing.pause()
        clearInterval(idAudioIntervalRef.current)
        setTimeout(() => setCallStatus('conversation'),1000)
      })
      peer.on("close", () => setCallStatus('hanging up...'));
      peer.on('error', () => setCallStatus('connection lost'))
      socket.on("acceptedCall", ({ signal }: any) => {
        if (signal === 'declined') setCallStatus('request declined')
          else if (signal === 'busy') setCallStatus('line busy')
           else peer.signal(signal)
      });
      connectionRef.current = peer;
    } catch (e:any) {
      setCallStatus('permission not allowed')
    } 
  },[socketId,companionId,_id,mySocket,myVideoRef,setCallStatus])

  const handleAnswerCall = useCallback(async () => {
    try {
      setCallStatus('waiting...')
      audioHtml.pause()
      const stream = await navigator.mediaDevices.getUserMedia({
        video: true,
        audio: true
      })
      setMyStream(stream)
      myVideoRef.current.srcObject = stream;
      const peer = new Peer({
        initiator: false,
        trickle: false,
        stream,
      });
      peer.on("signal", (data: any) => {
        socket.emit("answerCall", {
          signal: data,
          to: companionSocket,
        });
      });
      peer.on("stream", (companionStream: any) => {
        companionVideoRef.current.srcObject = companionStream;
        companionAudioRef.current.srcObject = companionStream;
      });
      peer.on('connect', () => {
        setCallStatus('connection')
        setAlert('')
        setTimeout(() => setCallStatus('conversation'),1000)
      })
      peer.on("close", () => setCallStatus('hanging up...'));
      peer.on('error', () => setCallStatus('connection lost'))
      peer.signal(companionSignal);
      connectionRef.current = peer;
    } catch (e: any) {
      setCallStatus('permission not allowed')
    }
  }, [companionSocket, companionSignal, setCallStatus,audioHtml])
  
  useEffect(() => {
    socket.on("me", (id: string) => {
      setMySocket(id)
      socketIdChat(id)
    })
  },[])

  useEffect(() => {
    socket.on('incomeCall', ({ name, lastName, avatarUrl, color, number, from, signal }: any) => {
      if (connectionRef.current === null) {
        setCallStatus('is calling you')
        setName(name)
        setLastName(lastName)
        setAvatarUrl(avatarUrl)
        setColor(color)
        setNumber(number)
        setCompanionSocket(from)
        setCompanionSignal(signal)
        const audioRing = playNotification(`${prodBaseURL}/ringing.mp3`)
        audioRing.loop = true
        setAudioHtml(audioRing)
      } else if (companionSocket !== from) {
        socket.emit("answerCall", {
          signal: 'busy',
          to: companionSocket,
        });
      }
    })
  }, [setCallStatus,companionSocket])

  useEffect(() => {
    if (callLast === 60) setCallStatus('have not got response')
  }, [callLast, setCallStatus])
  
  useEffect(() => {
    if(callStatus === 'requesting...') handleStartCall()
  }, [callStatus, handleStartCall])

  useEffect(() => {
    if (callStatus === 'hanging up...' || callStatus === 'connection lost'
      || callStatus === 'request declined' || callStatus === 'have not got response'
      || callStatus === 'permission not allowed' || callStatus === 'line busy')
      handleLeaveCall()
  }, [callStatus, handleLeaveCall, setCallStatus])
 
  useEffect(() => {
    if (callStatus === '') {
      setName(chat.name)
      setLastName(chat.lastName)
      setAvatarUrl(chat.avatarUrl)
      setColor(chat.color)
      setNumber(chat.number)
    }
  }, [callStatus, chat])

  return (
    <div className={classes.container} style={{ top: callStatus ? 0 : '-100%'}}>
      <video className={classes.myVideo} style={{width: !myStream || mutedMyVideo?0:250,height: !myStream || mutedMyVideo?0:'auto'}}
        ref={myVideoRef} playsInline autoPlay muted controls={false} />
      <Moveable
        target={myVideoRef.current}
        draggable={true}
        throttleDrag={0}
        hideDefaultLines={true}
        renderDirections={[]}
        rotationPosition="none"
        origin={false}
        onDrag={({ target, transform }: OnDrag) =>
          target!.style.transform = transform }
      />
      <div className={classes.modalCall} style={{width: fullScreen?'100vw':'34vw',height:fullScreen?'100vh':'auto'}}>
        <div className={classes.rightIcons}>
          <div className={classes.rightIconWrapper} onClick={() => setFullScreen(false)}
           style={{backgroundColor:fullScreen?'rgb(36, 36, 36)':'rgb(70, 70, 70)'}}>
            <MinimizeIcon fontSize='small' />
          </div>
          <div className={classes.rightIconWrapper} onClick={() => setFullScreen(true)}
           style={{backgroundColor:fullScreen?'rgb(70, 70, 70)':'rgb(36, 36, 36)'}}>
            <CropLandscapeIcon fontSize='small' />
          </div>
          <div className={classes.rightIconWrapperClose} onClick={handleHangUp}>
            <CloseIcon fontSize='small' />
          </div>
        </div>
        <div style={{ width: '100%', position: "relative" }}>
          {alert && <Alert variant="filled" severity="info" sx={{ backgroundColor: "rgb(70, 70, 70)" }}
            style={{ width: fullScreen?'auto':"100%", position: 'absolute', left: 0, bottom: -48 }}>{alert}</Alert>}
          {!fullScreen && <>
            <ListItemAvatar style={{margin:'25px 0px 5px 0px'}}>
              <Avatar alt={name} src={avatarUrl?`${prodAwsS3}/${avatarUrl}`:undefined}
                sx={{ background: color, width: 120, height: 120, marginRight: 2, fontSize:30,zIndex:0,margin:'0 auto'}}>
                {`${firstLetter(name)}${firstLetter(lastName)}`}
              </Avatar>
            </ListItemAvatar>
            <ListItemText primary={`${firstLetter(name)}${slicedWord(name, 15, 1)}
              ${firstLetter(lastName)}${slicedWord(lastName, 15, 1)}`}
              primaryTypographyProps={{ color: '#dfdfdf', fontSize: 20, fontWeight: 500,textAlign: "center" }}/>
            <ListItemText primary={number} primaryTypographyProps={{ color: '#ffffff', fontSize: 15, fontWeight: 500, textAlign: "center" }} />
            <ListItemText secondary={callStatus} secondaryTypographyProps={{ color: "#dfdfdf", textAlign: "center" }} />
            <ListItemText secondary={conversationLast} secondaryTypographyProps={{ color: "#dfdfdf", textAlign: "center" }} />
          </>}
        </div>
        <video ref={companionVideoRef} playsInline muted autoPlay controls={false}
          style={{width: '100%',height:fullScreen?'100vh': 'auto',objectFit: 'cover',
          backgroundColor:'rgb(36, 36, 36)'}} onTimeUpdate={handleConversationLast} />
        <audio ref={companionAudioRef} autoPlay />
        <div className={classes.bottomWrapper}>
          <div className={classes.bottomItem} onClick={handleMuteVideo}>
            <Avatar className={classes.bottomIcon} 
              sx={{backgroundColor: mutedMyVideo?'#ffffff':'rgb(88, 88, 88)',color: mutedMyVideo?'rgb(36, 36, 36)':'#ffffff', width: 44, height: 44,zIndex:0}}>
              {mutedMyVideo?<VideocamOffIcon fontSize="medium" />:<VideocamIcon fontSize="medium" />}
            </Avatar>
            <Typography variant="h6" className={classes.titleIconBottom}>{mutedMyVideo?'Start Video':'Stop Video'}</Typography>
          </div>
          <div className={classes.bottomItem}>
            <Avatar className={classes.bottomIconEndAccept} onClick={handleHangUp}
              sx={{backgroundColor: '#f02a2a',color: '#ffffff', width: 44, height: 44,zIndex:0}}>
              <CallEndIcon fontSize="medium" />
            </Avatar>
            <Typography variant="h6" className={classes.titleIconBottom}>
              {callStatus === 'is calling you' ? 'Decline' : 'End Call'}
            </Typography>
          </div>
          {callStatus === 'is calling you' &&
          <div className={classes.bottomItem} style={{position:"relative"}}>
            <div className={classes.ringPulsate}></div>
            <Avatar className={classes.bottomIconEndAccept} onClick={handleAnswerCall}
              sx={{ backgroundColor: '#21f519', color: '#ffffff', width: 44, height: 44, zIndex: 0 }}>
              <PhoneIcon fontSize="medium" />
            </Avatar>
            <Typography variant="h6" className={classes.titleIconBottom}>
              Accept
            </Typography>
          </div>}          
          <div className={classes.bottomItem}>
            <Avatar className={classes.bottomIcon} onClick={handleMuteAudio}
              sx={{backgroundColor: mutedMyAudio?'#ffffff':'rgb(88, 88, 88)',color: mutedMyAudio?'rgb(36, 36, 36)':'#ffffff', width: 44, height: 44,zIndex:0}}>
              {mutedMyAudio?<MicOffIcon fontSize="medium" />:<MicIcon fontSize="medium" />}
            </Avatar>
            <Typography variant="h6" className={classes.titleIconBottom}>{mutedMyAudio?'Unmute':'Mute'}</Typography>
          </div>
        </div>
      </div>
    </div>      
   )
}

export default CallBar