import { AzureCommunicationTokenCredential, createIdentifierFromRawId } from '@azure/communication-common';
import { CallClient, LocalVideoStream, VideoStreamRenderer } from '@azure/communication-calling';

class VideoCall {
  constructor() {
    //this.isLocalVideoStartedChangedCallback = null;
    //this.localVideoStreamsUpdatedCallback = null;
    //this.onCreateLocalVideoStreamCallback = null;
    this.onGetServerCallIDCallback = null;
    //this.remoteParticipantStateChangedCallback = null;
    //this.remoteParticipantsUpdatedCallback = null;
    //this.remoteVideoIsAvailableChangedCallback = null;
    this.stateChangedCallback = null;
    this.callEndedCallback = null;
    this.participantsJoinedCallback = null;
    this.callsUpdatedCallback = null;

    this.callAdapter = null;
    this.videoContainer = null;
    this.displayName = null;
    this.roomID = null;
    this.token = null;
    this.userID = null;

    this.onFetchParticipantMenuItemsCallback = null;
    this.onFetchCustomButtonPropsCallbacks = [];
    this.onAddParticipantCallback = null;
  }

  async init(options) {
    let self = this;
    this.stateChangedCallback = options.stateChangedCallback;
    /*this.remoteParticipantsUpdatedCallback = options.remoteParticipantsUpdated;*/
    /*this.isLocalVideoStartedChangedCallback = options.isLocalVideoStartedChanged;*/
    /*this.localVideoStreamsUpdatedCallback = options.localVideoStreamsUpdated;*/
    this.idChangedCallback = options.idChanged;
    //this.onCreateLocalVideoStreamCallback = options.onCreateLocalVideoStream;
    //this.remoteParticipantStateChangedCallback = options.remoteParticipantStateChanged;
    //this.remoteVideoIsAvailableChangedCallback = options.remoteVideoIsAvailableChanged;
    this.onGetServerCallIDCallback = options.onGetServerCallIDCallback;
    this.callEndedCallback = options.callEndedCallback;
    this.participantsJoinedCallback = options.participantsJoinedCallback;
    this.onFetchParticipantMenuItemsCallback = options.onFetchParticipantMenuItemsCallback;
    this.onFetchCustomButtonPropsCallbacks = options.onFetchCustomButtonPropsCallbacks || [];
    this.onAddParticipantCallback = options.onAddParticipantCallback;

    this.callAdapter = options.callAdapter;
    this.videoContainer = options.videoContainer;
    this.displayName = options.displayName;
    this.roomID = options.roomID;
    this.token = options.token;
    this.userID = options.userID;

    this.serverCallId;

    const callControls = {
      // Hide all default buttons
      cameraButton: true,
      endCallButton: false,
      microphoneButton: false,
      participantsButton: true,
      screenShareButton: false,
      devicesButton: false,
      moreButton: false,
      raiseHandButton: false,
      reactionButton: false,
      dtmfDialerButton: false,
      holdButton: false,
      peopleButton: false,
      exitSpotlightButton: false,
      captionsButton: false,
      galleryControlsButton: false,
      teamsMeetingPhoneCallButton: false,
      displayType: 'compact',

      // Hide the entire control bar if needed
      onFetchCustomButtonProps: this.onFetchCustomButtonPropsCallbacks
    };

    const isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
    const callCompositeProps = {
      callControls: callControls,
      formFactor: isMobile ? 'mobile' : 'desktop',
      onFetchParticipantMenuItems: this.onFetchParticipantMenuItemsCallback,
      options: {
        callControls: callControls
      }
    };

    const adapterArgs = {
      userId: createIdentifierFromRawId(this.userID),
      //credential: new AzureCommunicationTokenCredential(this.token),
      token: this.token,
      displayName: this.displayName,
      locator: { roomId: this.roomID },
      callAdapterOptions: {},
      callCompositeOptions: callCompositeProps
    };

    this.callAdapter = await callComposite.loadCallComposite(
      adapterArgs,
      this.videoContainer, // container element,
      callCompositeProps
    );

    //this.callAdapter.callAgent.on("callsUpdated", function (e) {
    //  e.added.forEach((addedCall) => {
    //    addedCall.on('stateChanged', (state) => this.stateChanged(addedCall));
    //  });
    //});

    this.callAdapter.on("callIdChanged", function (e) {
    });

    this.callAdapter.onStateChange(state => {
      if (state.call?.info && !this.serverCallId) {
        state.call.info.getServerCallId().then(result => {
          this.serverCallId = result;
          this.onGetServerCallIDCallback?.(result);
        }).catch(err => {
          console.log(err);
        });
      }
    });

    this.callAdapter.on("callEnded", function (e) {
      self.callEndedCallback?.(e);
    });

    this.callAdapter.on("participantsJoined", function (e, f) {
      self.participantsJoinedCallback?.(e, f);
    });

    this.callAdapter.on("onAddParticipant", function (e, f) {
      self.onAddParticipantCallback?.(e, f);
    });

    //CallEnded

    return this.callAdapter;
  }

  //stopLocalVideo() {
  //  if (this.call) {
  //    this.call.stopVideo(this.localVideoStream);
  //  }
  //}

  async joinRoom() {
    await this.callAdapter?.joinCall({
      microphoneOn: true,
      cameraOn: true
    });
  }

  async stopCall(forEveryone = false) {
    await this.callAdapter?.leaveCall(forEveryone);
  }

  //async subscribeToCall(call) {
  //  try {
  //    call.on('idChanged', () => {
  //      this.idChanged?.(call.id);
  //    });
  //    call.on('stateChanged', async () => {
  //      this.stateChangedCallback?.(call.state);
  //    });
  //    call.on('isLocalVideoStartedChanged', () => {
  //      this.isLocalVideoStartedChanged?.(call.isLocalVideoStarted);
  //    });
  //    call.on('localVideoStreamsUpdated', e => {
  //      this.localVideoStreamsUpdated?.(e);
  //    });

  //    // Subscribe to the call's 'remoteParticipantsUpdated' event to be
  //    // notified when new participants are added to the call or removed from the call.
  //    call.on('remoteParticipantsUpdated', e => {
  //      this.remoteParticipantsUpdated?.(e);

  //      e.added.forEach(remoteParticipant => {
  //        this.subscribeToRemoteParticipant(remoteParticipant)
  //      });
  //      // Unsubscribe from participants that are removed from the call
  //      e.removed.forEach(remoteParticipant => {
  //        console.log('Remote participant removed from the call.');
  //      });
  //    });

  //    call.localVideoStreams.forEach(async (lvs) => {
  //      this.localVideoStream = lvs;
  //      await this.displayLocalVideoStream(lvs);
  //    });

  //    // Inspect the call's current remote participants and subscribe to them.
  //    call.remoteParticipants.forEach(remoteParticipant => {
  //      this.subscribeToRemoteParticipant(remoteParticipant);
  //    });
  //  } catch (error) {
  //    console.error(error);
  //  }
  //}

  //subscribeToRemoteParticipant(remoteParticipant) {
  //  try {
  //    // Inspect the initial remoteParticipant.state value.
  //    console.log(`Remote participant state: ${remoteParticipant.state}`);
  //    // Subscribe to remoteParticipant's 'stateChanged' event for value changes.
  //    remoteParticipant.on('stateChanged', () => {
  //      console.log(`Remote participant state changed: ${remoteParticipant.state}`, JSON.stringify(remoteParticipant));
  //      this.remoteParticipantStateChanged?.(remoteParticipant.state);
  //    });

  //    // Inspect the remoteParticipants's current videoStreams and subscribe to them.
  //    remoteParticipant.videoStreams.forEach(remoteVideoStream => {
  //      this.subscribeToRemoteVideoStream(remoteVideoStream);
  //    });
  //    // Subscribe to the remoteParticipant's 'videoStreamsUpdated' event to be
  //    // notified when the remoteParticipant adds new videoStreams and removes video streams.
  //    remoteParticipant.on('videoStreamsUpdated', e => {
  //      // Subscribe to new remote participant's video streams that were added.
  //      e.added.forEach(remoteVideoStream => {
  //        this.subscribeToRemoteVideoStream(remoteVideoStream);
  //      });
  //      // Unsubscribe from remote participant's video streams that were removed.
  //      e.removed.forEach(remoteVideoStream => {
  //        console.log('Remote participant video stream was removed.');
  //      })
  //    });
  //  } catch (error) {
  //    console.error(error);
  //  }
  //}

  //async subscribeToRemoteVideoStream(remoteVideoStream) {
  //  let renderer = new VideoStreamRenderer(remoteVideoStream);
  //  let view;

  //  const createView = async () => {
  //    // Create a renderer view for the remote video stream.
  //    view = await renderer.createView();
  //    this.remoteVideoIsAvailableChanged?.({
  //      isAvailable: remoteVideoStream.isAvailable,
  //      participantId: remoteVideoStream.tsParticipantId,
  //      el: view.target
  //    });
  //  }

  //  // Remote participant has switched video on/off
  //  remoteVideoStream.on('isAvailableChanged', async () => {
  //    try {
  //      if (remoteVideoStream.isAvailable) {
  //        await createView();
  //      } else {
  //        view?.dispose();
  //      }
  //    } catch (e) {
  //      console.error(e);
  //    }
  //  });

  //  // Remote participant has video on initially.
  //  if (remoteVideoStream.isAvailable) {
  //    try {
  //      await createView();
  //    } catch (e) {
  //      console.error(e);
  //    }
  //  }
  //}

  //async createLocalVideoStream() {
  //  const camera = (await this.deviceManager.getCameras())[0];
  //  if (camera) {
  //    return new LocalVideoStream(camera);
  //  } else {
  //    console.error(`No camera device found on the system`);
  //  }
  //}

  leaveRoom() {
    if (this.call) {
      this.call.hangUp();
    }
  }

  //createIdentifierFromRawId(rawId) {
  //  return createIdentifierFromRawId(rawId);
  //}

  //async displayLocalVideoStream(lvs) {
  //  try {
  //    let localVideoStreamRenderer = new VideoStreamRenderer(lvs);
  //    const view = await localVideoStreamRenderer.createView();
  //    this.onCreateLocalVideoStream?.(view.target);
  //  } catch (error) {
  //    console.error(error);
  //  }
  //}
}

export default VideoCall;