import React, { useState, useEffect, useRef } from 'react';
import axios from 'axios';
import WebRTCManager from '../../utils/webrtc';
import './Call.css';

const Call = ({ socket, conversationId, participants, onCallEnd }) => {
  const [callId, setCallId] = useState(null);
  const [callStatus, setCallStatus] = useState('idle'); // idle, initiating, ringing, connected, ended
  const [isAudioEnabled, setIsAudioEnabled] = useState(true);
  const [isVideoEnabled, setIsVideoEnabled] = useState(true);
  const [isScreenSharing, setIsScreenSharing] = useState(false);
  const [callDuration, setCallDuration] = useState(0);
  const [connectionQuality, setConnectionQuality] = useState('good'); // good, fair, poor
  const [remoteParticipants, setRemoteParticipants] = useState([]);
  const [error, setError] = useState(null);
  
  const webrtcManager = useRef(null);
  const localVideoRef = useRef(null);
  const remoteVideosRef = useRef(new Map());
  const callStartTime = useRef(null);
  const durationInterval = useRef(null);
  const statsInterval = useRef(null);
  
  /**
   * Initialize WebRTC manager
   */
  useEffect(() => {
    if (!socket) return;
    
    webrtcManager.current = new WebRTCManager(socket);
    
    // Setup event handlers
    webrtcManager.current.onRemoteStream = handleRemoteStream;
    webrtcManager.current.onRemoteStreamRemoved = handleRemoteStreamRemoved;
    webrtcManager.current.onConnectionStateChange = handleConnectionStateChange;
    
    return () => {
      if (webrtcManager.current) {
        webrtcManager.current.cleanup();
      }
      clearInterval(durationInterval.current);
      clearInterval(statsInterval.current);
    };
  }, [socket]);
  
  /**
   * Listen for incoming calls
   */
  useEffect(() => {
    if (!socket) return;
    
    socket.on('call:incoming', handleIncomingCall);
    socket.on('call:ended', handleCallEnded);
    
    return () => {
      socket.off('call:incoming', handleIncomingCall);
      socket.off('call:ended', handleCallEnded);
    };
  }, [socket]);
  
  /**
   * Update call duration timer
   */
  useEffect(() => {
    if (callStatus === 'connected' && !durationInterval.current) {
      callStartTime.current = Date.now();
      durationInterval.current = setInterval(() => {
        const duration = Math.floor((Date.now() - callStartTime.current) / 1000);
        setCallDuration(duration);
      }, 1000);
    } else if (callStatus !== 'connected' && durationInterval.current) {
      clearInterval(durationInterval.current);
      durationInterval.current = null;
    }
    
    return () => {
      if (durationInterval.current) {
        clearInterval(durationInterval.current);
      }
    };
  }, [callStatus]);
  
  /**
   * Monitor connection quality
   */
  useEffect(() => {
    if (callStatus === 'connected' && !statsInterval.current) {
      statsInterval.current = setInterval(async () => {
        if (webrtcManager.current && remoteParticipants.length > 0) {
          const firstParticipant = remoteParticipants[0];
          const stats = await webrtcManager.current.getConnectionStats(firstParticipant.userId);
          
          if (stats && stats.connection) {
            const rtt = stats.connection.roundTripTime || 0;
            const bitrate = stats.connection.availableOutgoingBitrate || 0;
            
            // Determine quality based on RTT and bitrate
            if (rtt < 0.1 && bitrate > 500000) {
              setConnectionQuality('good');
            } else if (rtt < 0.3 && bitrate > 200000) {
              setConnectionQuality('fair');
            } else {
              setConnectionQuality('poor');
            }
          }
        }
      }, 3000);
    } else if (callStatus !== 'connected' && statsInterval.current) {
      clearInterval(statsInterval.current);
      statsInterval.current = null;
    }
    
    return () => {
      if (statsInterval.current) {
        clearInterval(statsInterval.current);
      }
    };
  }, [callStatus, remoteParticipants]);
  
  /**
   * Handle incoming call
   */
  const handleIncomingCall = async (data) => {
    console.log('Incoming call:', data);
    setCallId(data.callId);
    setCallStatus('ringing');
    setRemoteParticipants(data.participants || []);
  };
  
  /**
   * Handle remote stream received
   */
  const handleRemoteStream = (userId, stream) => {
    console.log('Remote stream received from:', userId);
    
    // Get or create video element for this user
    const videoElement = remoteVideosRef.current.get(userId);
    if (videoElement) {
      videoElement.srcObject = stream;
    }
  };
  
  /**
   * Handle remote stream removed
   */
  const handleRemoteStreamRemoved = (userId) => {
    console.log('Remote stream removed from:', userId);
    setRemoteParticipants(prev => prev.filter(p => p.userId !== userId));
  };
  
  /**
   * Handle connection state change
   */
  const handleConnectionStateChange = (userId, state) => {
    console.log(`Connection state with ${userId}:`, state);
    
    if (state === 'connected') {
      setCallStatus('connected');
    } else if (state === 'failed' || state === 'disconnected') {
      setError(`Connection ${state} with user ${userId}`);
    }
  };
  
  /**
   * Handle call ended
   */
  const handleCallEnded = (data) => {
    console.log('Call ended:', data);
    setCallStatus('ended');
    
    if (webrtcManager.current) {
      webrtcManager.current.cleanup();
    }
    
    if (onCallEnd) {
      onCallEnd(data);
    }
  };
  
  /**
   * Initiate a new call
   */
  const initiateCall = async (type = 'video') => {
    try {
      setCallStatus('initiating');
      setError(null);
      
      // Get TURN credentials
      const turnResponse = await axios.get('/api/calls/turn-credentials', {
        headers: { Authorization: `Bearer ${localStorage.getItem('token')}` }
      });
      
      if (webrtcManager.current && turnResponse.data.credentials) {
        await webrtcManager.current.setTurnCredentials(turnResponse.data.credentials);
      }
      
      // Initialize local media stream
      const audioEnabled = true;
      const videoEnabled = type === 'video';
      
      if (webrtcManager.current) {
        const localStream = await webrtcManager.current.initializeLocalStream(audioEnabled, videoEnabled);
        
        // Display local video
        if (localVideoRef.current) {
          localVideoRef.current.srcObject = localStream;
        }
      }
      
      // Initiate call via API
      const response = await axios.post('/api/calls/initiate', {
        conversationId: conversationId,
        type: type,
        participantIds: participants.map(p => p.userId)
      }, {
        headers: { Authorization: `Bearer ${localStorage.getItem('token')}` }
      });
      
      const { callId: newCallId } = response.data;
      setCallId(newCallId);
      setCallStatus('ringing');
      
      if (webrtcManager.current) {
        webrtcManager.current.currentCallId = newCallId;
        webrtcManager.current.isInitiator = true;
        
        // Create peer connections for each participant
        for (const participant of participants) {
          await webrtcManager.current.initiateCallToUser(participant.userId);
        }
      }
      
      setRemoteParticipants(participants);
    } catch (err) {
      console.error('Error initiating call:', err);
      setError(err.response?.data?.message || err.message || 'Failed to initiate call');
      setCallStatus('idle');
    }
  };
  
  /**
   * Answer incoming call
   */
  const answerCall = async () => {
    try {
      setError(null);
      
      // Get TURN credentials
      const turnResponse = await axios.get('/api/calls/turn-credentials', {
        headers: { Authorization: `Bearer ${localStorage.getItem('token')}` }
      });
      
      if (webrtcManager.current && turnResponse.data.credentials) {
        await webrtcManager.current.setTurnCredentials(turnResponse.data.credentials);
      }
      
      // Initialize local media stream
      if (webrtcManager.current) {
        const localStream = await webrtcManager.current.initializeLocalStream(true, true);
        
        // Display local video
        if (localVideoRef.current) {
          localVideoRef.current.srcObject = localStream;
        }
      }
      
      // Answer call via API
      await axios.post(`/api/calls/${callId}/answer`, {}, {
        headers: { Authorization: `Bearer ${localStorage.getItem('token')}` }
      });
      
      setCallStatus('connected');
    } catch (err) {
      console.error('Error answering call:', err);
      setError(err.response?.data?.message || err.message || 'Failed to answer call');
      setCallStatus('idle');
    }
  };
  
  /**
   * Reject incoming call
   */
  const rejectCall = async () => {
    try {
      await axios.post(`/api/calls/${callId}/reject`, {}, {
        headers: { Authorization: `Bearer ${localStorage.getItem('token')}` }
      });
      
      setCallStatus('idle');
      setCallId(null);
    } catch (err) {
      console.error('Error rejecting call:', err);
      setError(err.response?.data?.message || err.message || 'Failed to reject call');
    }
  };
  
  /**
   * End active call
   */
  const endCall = async () => {
    try {
      if (callId) {
        await axios.post(`/api/calls/${callId}/end`, {}, {
          headers: { Authorization: `Bearer ${localStorage.getItem('token')}` }
        });
      }
      
      if (webrtcManager.current) {
        webrtcManager.current.cleanup();
      }
      
      setCallStatus('ended');
      setCallId(null);
      
      if (onCallEnd) {
        onCallEnd({ reason: 'ended-by-user' });
      }
    } catch (err) {
      console.error('Error ending call:', err);
      setError(err.response?.data?.message || err.message || 'Failed to end call');
    }
  };
  
  /**
   * Toggle audio on/off
   */
  const toggleAudio = async () => {
    if (webrtcManager.current) {
      const enabled = !isAudioEnabled;
      webrtcManager.current.toggleAudio(enabled);
      setIsAudioEnabled(enabled);
      
      // Update media state via API
      if (callId) {
        try {
          await axios.patch(`/api/calls/${callId}/media`, {
            audioEnabled: enabled
          }, {
            headers: { Authorization: `Bearer ${localStorage.getItem('token')}` }
          });
        } catch (err) {
          console.error('Error updating media state:', err);
        }
      }
    }
  };
  
  /**
   * Toggle video on/off
   */
  const toggleVideo = async () => {
    if (webrtcManager.current) {
      const enabled = !isVideoEnabled;
      webrtcManager.current.toggleVideo(enabled);
      setIsVideoEnabled(enabled);
      
      // Update media state via API
      if (callId) {
        try {
          await axios.patch(`/api/calls/${callId}/media`, {
            videoEnabled: enabled
          }, {
            headers: { Authorization: `Bearer ${localStorage.getItem('token')}` }
          });
        } catch (err) {
          console.error('Error updating media state:', err);
        }
      }
    }
  };
  
  /**
   * Toggle screen sharing
   */
  const toggleScreenShare = async () => {
    if (webrtcManager.current) {
      try {
        if (isScreenSharing) {
          webrtcManager.current.stopScreenShare();
          setIsScreenSharing(false);
          
          // Restore local video
          if (localVideoRef.current && webrtcManager.current.getLocalStream()) {
            localVideoRef.current.srcObject = webrtcManager.current.getLocalStream();
          }
        } else {
          const screenStream = await webrtcManager.current.startScreenShare();
          setIsScreenSharing(true);
          
          // Display screen in local video
          if (localVideoRef.current) {
            localVideoRef.current.srcObject = screenStream;
          }
        }
      } catch (err) {
        console.error('Error toggling screen share:', err);
        setError('Failed to share screen');
      }
    }
  };
  
  /**
   * Format call duration (HH:MM:SS or MM:SS)
   */
  const formatDuration = (seconds) => {
    const hours = Math.floor(seconds / 3600);
    const minutes = Math.floor((seconds % 3600) / 60);
    const secs = seconds % 60;
    
    if (hours > 0) {
      return `${hours}:${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
    }
    return `${minutes}:${secs.toString().padStart(2, '0')}`;
  };
  
  /**
   * Render call controls
   */
  const renderControls = () => {
    if (callStatus === 'ringing' && !webrtcManager.current?.isInitiator) {
      return (
        <div className="call-controls">
          <button className="control-btn accept-btn" onClick={answerCall}>
            <span className="icon">📞</span>
            Answer
          </button>
          <button className="control-btn reject-btn" onClick={rejectCall}>
            <span className="icon">📵</span>
            Reject
          </button>
        </div>
      );
    }
    
    if (callStatus === 'connected' || callStatus === 'ringing') {
      return (
        <div className="call-controls">
          <button 
            className={`control-btn ${isAudioEnabled ? 'active' : 'inactive'}`} 
            onClick={toggleAudio}
          >
            <span className="icon">{isAudioEnabled ? '🎤' : '🔇'}</span>
          </button>
          
          <button 
            className={`control-btn ${isVideoEnabled ? 'active' : 'inactive'}`} 
            onClick={toggleVideo}
          >
            <span className="icon">{isVideoEnabled ? '📹' : '🚫'}</span>
          </button>
          
          <button 
            className={`control-btn ${isScreenSharing ? 'active' : ''}`} 
            onClick={toggleScreenShare}
          >
            <span className="icon">🖥️</span>
          </button>
          
          <button className="control-btn end-btn" onClick={endCall}>
            <span className="icon">📵</span>
            End
          </button>
        </div>
      );
    }
    
    return null;
  };
  
  /**
   * Render connection quality indicator
   */
  const renderQualityIndicator = () => {
    if (callStatus !== 'connected') return null;
    
    const colors = {
      good: '#4CAF50',
      fair: '#FFC107',
      poor: '#F44336'
    };
    
    return (
      <div className="quality-indicator" style={{ backgroundColor: colors[connectionQuality] }}>
        {connectionQuality}
      </div>
    );
  };
  
  return (
    <div className="call-container">
      {error && (
        <div className="call-error">
          {error}
          <button onClick={() => setError(null)}>×</button>
        </div>
      )}
      
      <div className="call-header">
        <div className="call-status">
          {callStatus === 'ringing' && 'Calling...'}
          {callStatus === 'connected' && `Call Duration: ${formatDuration(callDuration)}`}
          {callStatus === 'ended' && 'Call Ended'}
        </div>
        {renderQualityIndicator()}
      </div>
      
      <div className="video-container">
        {/* Remote videos */}
        <div className="remote-videos">
          {remoteParticipants.map(participant => (
            <div key={participant.userId} className="remote-video-wrapper">
              <video
                ref={el => {
                  if (el) remoteVideosRef.current.set(participant.userId, el);
                }}
                autoPlay
                playsInline
                className="remote-video"
              />
              <div className="participant-name">{participant.userName || participant.userIdentifier}</div>
            </div>
          ))}
        </div>
        
        {/* Local video */}
        {(callStatus === 'ringing' || callStatus === 'connected') && (
          <div className="local-video-wrapper">
            <video
              ref={localVideoRef}
              autoPlay
              playsInline
              muted
              className="local-video"
            />
            <div className="local-label">You</div>
          </div>
        )}
      </div>
      
      {renderControls()}
      
      {callStatus === 'idle' && (
        <div className="call-actions">
          <button className="start-call-btn audio" onClick={() => initiateCall('audio')}>
            🎤 Start Audio Call
          </button>
          <button className="start-call-btn video" onClick={() => initiateCall('video')}>
            📹 Start Video Call
          </button>
        </div>
      )}
    </div>
  );
};

export default Call;
