import React, {useCallback, useEffect, useRef} from 'react';
import {EventsSocketsType} from '@config/constants';
import {SocketConnection} from '@config/socket/socket';
import {useGoBack} from '@hooks/useGoBack';
import {CallConnectionFeedback} from '@modules/calls/components';
import {Call} from '@modules/calls/interfaces';
import {callParticipantLeftCallback} from '@modules/calls/sockets';
import {removeCallId, resetState} from '@modules/calls/store';
import {
  useCallJoined,
  useGroupCall,
  useRemoteParticipants,
} from '@modules/calls/store/selectors';
import {CallService, isCallActive} from '@modules/calls/utils';

import {CallActiveLayout} from '../CallActiveLayout';
import {CallConnectingLayout} from '../CallConnectingLayout';

const socket = new SocketConnection();

interface Props {
  call: Call;
  isCaller: boolean;
}

export function CallContainer({call, isCaller}: Props) {
  const {goBack} = useGoBack();
  const remoteParticipants = useRemoteParticipants();
  const isGroupCall = useGroupCall()?.isGroupCall;
  const isCallJoined = useCallJoined();

  const hasConnectedOnce = useRef(false);
  const hasHandledEndRef = useRef(false);

  // For 1:1 calls, wait for at least 1 remote participant
  // For group calls, show layout immediately when joined
  const hasOtherParticipantsJoined =
    isGroupCall || remoteParticipants.length >= 1;

  if (hasOtherParticipantsJoined) {
    hasConnectedOnce.current = true;
  }

  useEffect(() => {
    if (isCallJoined && isCallActive(call)) {
      socket.listenEvent(
        EventsSocketsType.CALLS_CALL_PARTICIPANT_LEFT,
        callParticipantLeftCallback,
      );
    }
    return () => {
      socket.unListenEvent(EventsSocketsType.CALLS_CALL_PARTICIPANT_LEFT);
    };
  }, [call, isCallJoined]);

  // Dedupe goBack between the JS-driven hangup and the native END_CALL event.
  // On iOS, leaveCall emits END_CALL asynchronously (see CallManager.leaveCall),
  // so without this guard both paths call goBack and the native stack pops twice.
  const goBackOnce = useCallback(() => {
    if (hasHandledEndRef.current) return;
    hasHandledEndRef.current = true;
    goBack();
  }, [goBack]);

  const onHangupCall = useCallback(() => {
    CallService.leaveCurrentCall();
    removeCallId();
    resetState();
    goBackOnce();
  }, [goBackOnce]);

  useEffect(() => {
    const listener = CallService.registerEndCallListener(() => {
      goBackOnce();
    });

    return () => {
      listener.remove();
    };
  }, [goBackOnce]);

  if (!isCallJoined) {
    return <CallConnectionFeedback isLoading />;
  }

  if (hasConnectedOnce.current) {
    return <CallActiveLayout onHangupCall={onHangupCall} />;
  }

  return (
    <CallConnectingLayout onHangupCall={onHangupCall} isCaller={isCaller} />
  );
}
