import React, { useEffect, useMemo, useRef } from 'react';
import { useHistory, useLocation } from 'react-router-dom';
import Nav from '../../components/nav';
import RoomDialog from '../../components/dialog/room';
import { AgoraStream } from '../../utils/types';
import './room.scss';
import NativeSharedWindow from '../../components/native-shared-window';
import {roomStore, RTC_STATUS} from '../../stores/room';
import { useRoomState } from '../../containers/root-container';
import { globalStore } from '../../stores/global';
import { platform } from '../../utils/platform';
import AgoraWebClient, { AgoraStreamSpec, SHARE_ID } from '../../utils/agora-rtc-client';
import { AgoraElectronClient } from '../../utils/agora-electron-client';
import {eventBus} from "../../stores/EventBus";
import {
  Button,
  Dialog,
  DialogActions,
  DialogContent,
  DialogTitle,
  TextField
} from "@material-ui/core";
import {goHome} from "../../services/agora-end-points";

export const roomTypes = [
  {value: 0, text: 'One-on-One', path: 'one-to-one'},
  {value: 1, text: 'Small Class', path: 'small-class'},
  {value: 2, text: 'Large Class', path: 'big-class'},
];

export interface StarDialogProps {
  uid: number;
  keepMounted?: boolean;
  title: string;
  open: boolean;
  onClose: (uid:number , value: number) => void;
}

const NUMBER = /^[0-9]*/
function StarDialog(props: StarDialogProps) {
  let { onClose, title: valueProp, open, uid, ...other } = props;
  const [title, setTitle] = React.useState(valueProp);
  const [value, setValue] = React.useState<number>(0);
  React.useEffect(() => {
    if (!open) {
      setTitle(valueProp);
    }
  }, [valueProp, open]);

  const handleChange = (evt: any) => {

    let val = evt.target.value.match(NUMBER)[0];
    val = +val
    console.log('dialog handleChange ', val);
    if (!val || isNaN(val)) {
      setValue(0);
    } else {
      val = Math.abs(val)
      setValue(val);
    }

  };
  // const handleEntering = () => {
  //   // console.log('dialog handleEntering ');
  //   onClose(uid, value);
  //   setValue(0)
  // };

  const handleCancel = () => {
    console.log('dialog handleCancel ');
    onClose(-1, 0);
    setValue(0)
  };

  const handleOk = () => {
    // console.log('dialog handleOk ');
    onClose(uid, value);
    setValue(0)
  };



  return (
    <Dialog
      disableBackdropClick
      disableEscapeKeyDown
      maxWidth="xs"
      aria-labelledby="confirmation-dialog-title"
      open={open}
      {...other}
    >
      <DialogTitle id="confirmation-dialog-title">{title}</DialogTitle>
      <DialogContent >
        <TextField
          autoFocus
          margin="dense"
          id="starNumber"
          label="奖励值"
          type="text"
          value={value || ''}
          onChange={handleChange}
          fullWidth
        />
      </DialogContent>
      <DialogActions>
        <Button autoFocus onClick={handleCancel} color="primary">
          取消
        </Button>
        <Button onClick={handleOk} color="primary">
          确认
        </Button>
      </DialogActions>
    </Dialog>
  );
}




export function RoomPage({ children }: any) {

  const history = useHistory();

  const lock = useRef<boolean>(false);
  /////////////////////////
  const [open, setOpen] = React.useState(false);
  const [tid, setTid] = React.useState(0);
  const [title, setTitle] = React.useState('');
  const dialogLock = useRef<boolean>(false);

  const handleDialogClose = (uid:number, val:number) => {

    setOpen(false);
    dialogLock.current = false;
    if (uid < 0 || val <= 0) {
      return;
    }
    console.log('handleDialogClose', uid, val);
    roomStore.addStarToUser(uid, val);
  };


  const eventNames = eventBus.eventNames();
  if (!eventNames.includes('showAddStartDialog')) {
    console.log(3333333);
    eventBus.on('showAddStartDialog', (data) => {
      console.log('showAddStartDialog event')
      if (dialogLock.current) {
        return
      }

      dialogLock.current = true;
      let titleTxt = '全部学生'
      if (data.uid) {
        const stu = roomStore.state.users.get(`${data.uid}`);
        titleTxt = `学生：${stu?.account}`
      }

      setTid(+data.uid);
      setTitle(titleTxt);
      console.log('addStar', data);
      setTimeout(()=>setOpen(true))
    })
  }

  ///////////////////////////////////

  useEffect(() => {

    const me = roomStore.state.me;
    const rid = roomStore.state.course.rid;
    const roomType = roomStore.state.course.roomType;
    const roomName = roomStore.state.course.roomName;

    if (!rid || !me.uid) {
      // history.push('/');
      goHome(history)
    }

    const uid = me.uid;
    const payload = {
      uid,
      rid,
      role: me.role,
      roomName,
      roomType,
      video: me.video,
      audio: me.audio,
      chat: me.chat,
      account: me.account,
      token: '',
      boardId: me.boardId,
      linkId: me.linkId,
      sharedId: me.sharedId,
      lockBoard: me.lockBoard,
      grantBoard: me.grantBoard,
      stars: me.stars
    }
    lock.current = true;
    if (roomStore.state.rtm.joined) return;
    globalStore.showLoading();
    roomStore.loginAndJoin(payload, true).then(() => {
      roomStore.updateMe(payload).then(() => {
        lock.current && roomStore.updateSessionInfo(payload);
      }).catch((err: any) => {
        globalStore.showToast({
          type: 'rtmClient',
          message: 'login failure'
        });
        // history.push('/');
        goHome(history)
        console.warn(err)
      }).finally(() => {
        globalStore.stopLoading();
        lock.current = false;
      })
    }).catch((err: any) => {
      globalStore.showToast({
        type: 'rtmClient',
        message: 'login failure'
      });
      // history.push('/');
      goHome(history)
      console.warn(err)
    })
    .finally(() => {
      lock.current = false;
    });
  }, [history]);


  /*
  const loginFn = () => {

    const me = roomStore.state.me;
    const rid = roomStore.state.course.rid;
    const roomType = roomStore.state.course.roomType;
    const roomName = roomStore.state.course.roomName;

    if (!rid || !me.uid) {
      history.push('/');
    }

    const uid = me.uid;
    const payload = {
      uid,
      rid,
      role: me.role,
      roomName,
      roomType,
      video: me.video,
      audio: me.audio,
      chat: me.chat,
      account: me.account,
      token: '',
      boardId: me.boardId,
      linkId: me.linkId,
      sharedId: me.sharedId,
      lockBoard: me.lockBoard,
      grantBoard: me.grantBoard,
    }
    lock.current = true;
    if (roomStore.state.rtm.joined) return;
    globalStore.showLoading();
    roomStore.loginAndJoin(payload, true).then(() => {
      roomStore.updateMe(payload).then(() => {
        lock.current && roomStore.updateSessionInfo(payload);
      }).catch((err: any) => {
        globalStore.showToast({
          type: 'rtmClient',
          message: 'login failure'
        });
        history.push('/');
        console.warn(err)
      }).finally(() => {
        globalStore.stopLoading();
        lock.current = false;
      })
    }).catch((err: any) => {
      globalStore.showToast({
        type: 'rtmClient',
        message: 'login failure'
      });
      history.push('/');
      console.warn(err)
    })
      .finally(() => {
        lock.current = false;
      });
  }
  */

  const roomType = roomTypes[roomStore.state.course.roomType];

  const location = useLocation();

  const roomState = useRoomState();
  const me = roomStore.state.me;
  const course = roomStore.state.course;
  const classroom = Boolean(location.pathname.match(/classroom/));
  const isBigClass = Boolean(location.pathname.match(/big-class/));
  // const isSmallClass = Boolean(location.pathname.match(/small-class/));

  const prevRoute = useRef<string>(location.pathname);
  useEffect(() => {
    console.log("[route] prevRoute: ", prevRoute.current);
    return () => {
      globalStore.removeUploadNotice();
      roomStore.exitAll()
      .then(() => {
      })
      .catch(console.warn)
      .finally(() => {
      });
    }
  }, [location]);

  const rtc = useRef<boolean>(false);

  const canPublish = useMemo(() => {
    return !isBigClass ||
      (isBigClass &&
        (me.role === 'teacher' ||
          +me.uid === +course.linkId));
  }, [me.uid, course.linkId, me.role, isBigClass]);

  useEffect(() => {
    return () => {
      rtc.current = true
    }
  },[]);

  const publishLock = useRef<boolean>(false);

  const {rtcJoined, uid, role, mediaDevice, studentsOrder} = useMemo(() => {
    return {
      rtcJoined: roomState.rtc.joined,
      uid: roomState.me.uid,
      role: roomState.me.role,
      mediaDevice: roomState.mediaDevice,
      studentsOrder: roomState.studentsOrder
    }
  }, [roomState]);

  useEffect(() => {
    if (!location.pathname.match(/big-class/) || me.role === 'teacher') return
    if (course.linkId) return;
    const rtcClient = roomStore.rtcClient;
    if (platform === 'web') {
      const webClient = rtcClient as AgoraWebClient;
      if (!webClient.published) return;
      console.log('unpublish' ,2);
      webClient
        .unpublishLocalStream()
        .then(() => {
          console.log("[agora-web] unpublish local stream");
        }).catch(console.warn)
    }

    if (platform === 'electron') {
      const nativeClient = rtcClient as AgoraElectronClient;
      if (!nativeClient.published) return;
      nativeClient.unpublish();
    }

  }, [me.role, location.pathname, course.linkId]);

  useEffect( () => {
    const webClient = roomStore.rtcClient as AgoraWebClient;
    console.log('rtcJoined', rtcJoined, rtc.current);
    if (!rtcJoined) {
      // return;
      webClient.unpublishLocalStream()
    }

    if (!rtcJoined || rtc.current) return;

    if (platform === 'web') {
      const fn = () => {
        // console.log('check user publish stream, channelMeta', channelMeta);
        // console.log('check user publish stream, user orders', roomStore.state.studentsOrder);
        // console.log('check user publish stream, user info', roomStore.state.me);
        // const studentsOrder = channelMeta.studentsOrder || roomStore.state.studentsOrder;
        const studentsOrder = [...roomStore.state.studentsOrder];
        // const webClient = roomStore.rtcClient as AgoraWebClient;

        const uid = +roomStore.state.me.uid as number;
        const video =  studentsOrder.includes(uid) ? 1 : roomStore.state.me.video;
        const audio =  studentsOrder.includes(uid) ? 1 : roomStore.state.me.audio;
        const streamSpec: AgoraStreamSpec = {
          streamID: uid,
          video: !!video,
          audio: !!audio,
          mirror: false,
          screen: false,
          microphoneId: mediaDevice.microphoneId,
          cameraId: mediaDevice.cameraId,
          audioOutput: {
            volume: mediaDevice.speakerVolume,
            deviceId: mediaDevice.speakerId
          }
        }

        console.log("canPb>>> ", canPublish, roomStore.state.course.linkId, roomStore.state.me.uid);
        if (canPublish && !publishLock.current) {
          publishLock.current = true;
          webClient
            .publishLocalStream(streamSpec)
            .then(() => {
              console.log("[agora-web] publish local stream", roomStore.state.me.uid);
            }).catch(console.warn)
            .finally(() => {
              publishLock.current = false;
            })
        }
      }
      /*
      roomStore.rtmClient.getChannelAttributeBy(roomStore.state.course.rid).then((channelMeta: any) => {

      }).catch(err => {
        console.error(err)
        globalStore.showToast({
          type: 'rtmClient',
          message: err.message
        });
        history.push('/');
      });*/
      try{
        fn()
      } catch (err) {
        console.error(err)
        globalStore.showToast({
          type: 'rtmClient',
          message: err.message
        });
        // history.push('/');
        goHome(history)
      }

    }

    if (platform === 'electron' && rtcJoined) {
      const nativeClient = roomStore.rtcClient as AgoraElectronClient;
      if (canPublish && !publishLock.current) {
        publishLock.current = true;
        nativeClient.publish();
        publishLock.current = false;
      }
    }
    // eslint-disable-next-line
  }, [
    rtcJoined,
    uid,
    role,
    mediaDevice,
    canPublish
  ]);
  const checkPerMission = (status: string) => {
    // granted, denied, prompt
    if(status === 'granted'){
      globalStore.stopPermission();
    } else {
      globalStore.showPermission();
    }
  }
  useEffect(() => {
    navigator.permissions.query(
      // { name: 'camera' }
      { name: 'microphone' }
      // { name: 'geolocation' }
      // { name: 'notifications' }
      // { name: 'midi', sysex: false }
      // { name: 'midi', sysex: true }
      // { name: 'push', userVisibleOnly: true }
      // { name: 'push' } // without userVisibleOnly isn't supported in chrome M45, yet
    ).then(function(permissionStatus){
      checkPerMission(permissionStatus.state);
      permissionStatus.onchange = function(){
        checkPerMission(this.state);
      }
    });

    navigator.permissions.query(
      { name: 'camera' }
    ).then(function(permissionStatus){
      checkPerMission(permissionStatus.state);
      permissionStatus.onchange = function(){
        checkPerMission(this.state);
      }
    });
  }, []);
  useEffect(() => {

    const webClient = roomStore.rtcClient as AgoraWebClient;
    if (webClient.joined) {
      return;
    }
    webClient.rtc.on('stream-reconnect-start', (evt: any) => {
      console.log('[agora-web] stream-reconnect-start', evt);
    });
    webClient.rtc.on('connection-state-change', (evt: any) => {
      console.log('[agora-web] connection-state-change', evt);
    });
    webClient.rtc.on('reconnect', (evt: any) => {
      console.log('[agora-web] reconnect', evt);
    });
    webClient.rtc.on('connected', (evt: any) => {
      console.log('[agora-web] connected', evt);
    });
    webClient.rtc.on('stream-fallback', (evt: any) => {
      console.log('[agora-web] stream-fallback', evt);
    });
    webClient.rtc.on('stream-updated', (evt: any) => {
      console.log('[agora-web] stream-updated', evt);
    });
    webClient.rtc.on('exception', (evt: any) => {
      console.log('[agora-web] exception', evt);
    });
    webClient.rtc.on('onTokenPrivilegeWillExpire', (evt: any) => {
      // you need obtain the `newToken` token from server side
      const newToken = '';
      webClient.rtc.renewToken(newToken);
      console.log('[agora-web] onTokenPrivilegeWillExpire', evt);
    });
    webClient.rtc.on('onTokenPrivilegeDidExpire', (evt: any) => {
      // you need obtain the `newToken` token from server side
      const newToken = '';
      webClient.rtc.renewToken(newToken);
      console.log('[agora-web] onTokenPrivilegeDidExpire', evt);
    });
    webClient.rtc.on('error', (evt: any) => {
      console.log('[agora-web] error evt', evt);
    });
    webClient.rtc.on('stream-published', ({ stream }: any) => {
      const _stream = new AgoraStream(stream, stream.getId(), true);
      roomStore.addLocalStream(_stream);
    });
    webClient.rtc.on('stream-subscribed', ({ stream }: any) => {

      const streamID = stream.getId();
      console.log('stream', 2, 'stream-subscribed', streamID)
      // when streamID is not share_id use switch high or low stream in dual stream mode
      if (/*location.pathname.match(/small-class/) && */streamID !== SHARE_ID) {
        if (roomStore.state.course.teacherId
          && roomStore.state.course.teacherId === `${streamID}`) {
          webClient.setRemoteVideoStreamType(stream, 0);
          console.log("[agora-web] dual stream set high for teacher");
        }
        else {
          webClient.setRemoteVideoStreamType(stream, 1);
          console.log("[agora-web] dual stream set low for student");
        }
      }
      console.log('stream step:', 3,'uid', streamID, 'addRemoteStream to play')
      const _stream = new AgoraStream(stream, streamID, false);
      console.log("[agora-web] subscribe remote stream, id: ", stream.getId());
      roomStore.addRemoteStream(_stream);
    });
    webClient.rtc.on('stream-added', ({ stream }: any) => {
      console.log('stream', 1, 'stream-added')
      console.log("[agora-web] added remote stream, id: ", stream.getId());
      webClient.subscribe(stream);
      const uid = stream.getId();
      roomStore.setUserStreamStatus(+uid, RTC_STATUS.STREAM_ADDED)

    });
    webClient.rtc.on('stream-removed', ({ stream }: any) => {
      console.log("[agora-web] removed remote stream, id: ", stream.getId(), roomStore.applyUid);
      const id = stream.getId();
      if (id === roomStore.applyUid) {
        globalStore.removeNotice();
        roomStore.state.me.role === 'teacher' &&
        roomStore.updateCourseLinkUid(0).then(() => {
          console.log("update teacher link_uid to 0");
        }).catch(console.warn);
      }
      roomStore.removeRemoteStream(stream.getId());
    });
    webClient.rtc.on('peer-online', ({uid}: any) => {
      console.log("[agora-web] peer-online, id: ", uid);
      roomStore.addPeerUser(uid);
    });
    webClient.rtc.on('peer-leave', ({ uid }: any) => {
      console.log("[agora-web] peer-leave, id: ", uid, roomStore.applyUid);
      if (uid === roomStore.applyUid) {
        globalStore.removeNotice();
        me.role === 'teacher' &&
        roomStore.updateCourseLinkUid(0).then(() => {
          console.log("update teacher link_uid to 0");
        }).catch(console.warn);
      }
      roomStore.removePeerUser(uid);
      roomStore.removeRemoteStream(uid);
    });
    webClient.rtc.on("stream-fallback", ({ uid, attr }: any) => {
      const msg = attr === 0 ? 'resume to a&v mode' : 'fallback to audio mode';
      console.info(`[agora-web] stream: ${uid} fallback: ${msg}`);
    })
    // eslint-disable-next-line
  }, []);


  useEffect(() => {

    if (!roomState.me.uid || !roomState.course.rid) return;
    if (classroom) {
      if (platform === 'web') {
        const webClient = roomStore.rtcClient as AgoraWebClient;
        if (webClient.joined) {
          return;
        }
        console.log("[agora-rtc] add event listener");
        /* origin webClient.rtc.on in here */


        rtc.current = true;

        // WARN: IF YOU ENABLED APP CERTIFICATE, PLEASE SIGN YOUR TOKEN IN YOUR SERVER SIDE AND OBTAIN IT FROM YOUR OWN TRUSTED SERVER API
        console.info(1.1, 'rtc join')
        // if (roomState.me.role == 'teacher' || roomState.studentsOrder.includes(+roomState.me.uid)) {
        //   console.info( 'i m teacher should rtc join')
          webClient
            .joinChannel({
              uid: +roomState.me.uid,
              channel: roomState.course.rid,
              token: '',
              dual: true
            }).then(() => {

            console.info(2, 'rtc join ok', roomState.me.uid, [...studentsOrder], [...roomStore.state.studentsOrder], [...roomState.studentsOrder])
            if (roomState.me.role === 'teacher' || roomStore.state.studentsOrder.includes(+roomState.me.uid)) {
              roomStore.publishMeStream();
            }

            // // 如果当前用户是教师，直接发布，
            // if(roomStore.state.me.role == 'teacher') {
            //   roomStore.publishMeStream();
            // } else {
            //   // 看台上几个人里包含自己
            //   if (roomStore.state.studentsOrder.includes(+me.uid)) {
            //     roomStore.publishMeStream();
            //   }
            // }
          }).catch(console.warn).finally(() => {
            rtc.current = false;
          });
        // }

        return () => {
          console.log('exit')
          roomStore.removeRtcListener();
        }
      }
      /*
      if (platform === 'electron') {
        const rtcClient = roomStore.rtcClient;
        const nativeClient = rtcClient as AgoraElectronClient;
        if (nativeClient.joined) {
          console.log("[agora-electron] electron joined ", nativeClient.joined);
          return;
        }
        nativeClient.on('executefailed', (...args: any[]) => {
          console.warn("[agora-electron] executefailed", ...args);
        });
        nativeClient.on('error', (evt: any) => {
          console.warn('[agora-electron] error evt', evt);
        });
        // when trigger `joinedchannel` it means publish rtc stream success
        nativeClient.on('joinedchannel', (evt: any) => {
          console.log("[agora-electron stream-published")
          const stream = evt.stream;
          const _stream = new AgoraStream(stream, stream.uid, true);
          roomStore.addLocalStream(_stream);
        });
        // when trigger `userjoined` it means peer user & peer stream is online
        nativeClient.on('userjoined', (evt: any) => {
          const stream = evt.stream;
          const _stream = new AgoraStream(stream, stream.uid, false);
          if (location.pathname.match(/small-class/) && stream.uid !== SHARE_ID) {
            if (roomStore.state.course.teacherId
              && roomStore.state.course.teacherId === `${stream.uid}`) {
              const res = nativeClient.rtcEngine.setRemoteVideoStreamType(stream, 0);
              console.log("[agora-electron] dual stream set high for teacher, ", res);
            }
            else {
              const res = nativeClient.rtcEngine.setRemoteVideoStreamType(stream, 1);
              console.log("[agora-electron] dual stream set low for student, ", res);
            }
          }
          roomStore.addPeerUser(stream.uid);
          roomStore.addRemoteStream(_stream);
        });
        // when trigger `removestream` it means peer user & peer stream is offline
        nativeClient.on('removestream', ({ uid }: any) => {
          if (uid === roomStore.applyUid) {
            globalStore.removeNotice();
            me.role === 'teacher' &&
            roomStore.updateCourseLinkUid(0).then(() => {
              console.log("update teacher link_uid to 0");
            }).catch(console.warn);
          }
          roomStore.removePeerUser(uid);
          roomStore.removeRemoteStream(uid);
        });
        // WARN: IF YOU ENABLED APP CERTIFICATE, PLEASE SIGN YOUR TOKEN IN YOUR SERVER SIDE AND OBTAIN IT FROM YOUR OWN TRUSTED SERVER API
        nativeClient.joinChannel({
          uid: +roomState.me.uid,
          channel: roomState.course.rid,
          token: '',
          dual: isSmallClass
        });
        roomStore.setRTCJoined(true);
        return () => {
          const events = [
            'executefailed',
            'error',
            'joinedchannel',
            'userjoined',
            'removestream',
          ]
          for (let eventName of events) {
            nativeClient.off(eventName, () => {})
          }
          !rtc.current && nativeClient.exit();
          !rtc.current && roomStore.setRTCJoined(false);
          !rtc.current && roomStore.removeLocalStream();
        }
      }
      */

    }
    // eslint-disable-next-line
  }, [roomState.me.uid, roomState.course.rid]);

  useEffect(() => {
    const webClient = roomStore.rtcClient as AgoraWebClient;
      console.log('studentsOrder changed', webClient.joined, studentsOrder);
    if (!webClient.joined) {
      return;
    }
    if (me.role === 'student') {
      if (studentsOrder.includes(+me.uid)) {
        console.log(1.15,'stageup?', me.uid, 1111111  );
        roomStore.publishMeStream();
      } else {
        console.log(1.15,'stagedown?', me.uid, 222222  );
        roomStore.unPublishMeStream();
      }
      console.log(1.2 ,studentsOrder, 'studentsOrder changed publish stream');
    }
    // eslint-disable-next-line
  }, [studentsOrder]);

  return (
    <div className={`classroom ${roomType.path}`}>
      <StarDialog title={title} uid={tid} open={open} onClose={handleDialogClose}></StarDialog>
      <NativeSharedWindow />
      <Nav />
      {children}
      <RoomDialog />
    </div>
  );
}

