/**
 * Paarrot API Handler
 * 
 * This module handles API actions from the Electron API server.
 * It receives actions via IPC and executes them on the Matrix client.
 * 
 * To use this, import and call initPaarrotAPI() early in your app initialization.
 */

import { MatrixClient } from 'matrix-js-sdk';
import { getHomeRoomPath, getDirectRoomPath, getSpaceRoomPath } from './pages/pathUtils';
import { getCanonicalAliasOrRoomId, isRoomId } from './utils/matrix';
import { getCallService } from './features/call/useCall';
import { RoomType, StateEvent } from '../types/matrix/room';

/**
 * Global reference to the router navigate function
 * This is set by the router and used to navigate programmatically
 */
let navigateFunction: ((path: string) => void) | null = null;

/**
 * Track if the API has been initialized to prevent duplicate listeners
 */
let isInitialized = false;

/**
 * @param {any} room
 * @returns {boolean}
 */
function isSpaceLikeRoom(room: any): boolean {
  if (!room) return false;
  if (typeof room.isSpaceRoom === 'function' && room.isSpaceRoom()) return true;
  const roomKindEvent = room.currentState?.getStateEvents?.(StateEvent.PaarrotRoomKind, '');
  const roomKind = roomKindEvent?.getContent?.()?.kind;
  if (roomKind === 'forum_space') return true;
  const createEvent = room.currentState?.getStateEvents?.(StateEvent.RoomCreate, '');
  const roomType = createEvent?.getContent?.()?.type;
  return roomType === RoomType.Forum;
}

/**
 * Set the navigate function for programmatic navigation
 * Call this from your router setup
 */
export function setPaarrotNavigate(navigate: (path: string) => void) {
  navigateFunction = navigate;
  console.log('Paarrot API: Navigate function registered');
}

/**
 * Initialize the Paarrot API handler
 * This should be called once during app startup
 */
export function initPaarrotAPI(matrixClient: MatrixClient) {
  // Check if we're running in Electron
  if (!(window as any).electron?.api?.onAction) {
    console.log('Paarrot API: Not running in Electron, skipping API initialization');
    return;
  }

  // Prevent duplicate registrations
  if (isInitialized) {
    console.log('Paarrot API: Already initialized, skipping');
    return;
  }
  isInitialized = true;

  console.log('Paarrot API: Initializing API handler');

  // Listen for API actions from the Electron API server
  (window as any).electron.api.onAction(async (action: {
    action: string;
    params: any;
    responseChannel: string;
  }) => {
    console.log('Paarrot API: Received action:', action.action, action.params);

    try {
      let result;

      switch (action.action) {
        case 'get-status':
          result = await getStatus(matrixClient);
          break;

        case 'toggle-mute':
          result = await toggleMute(matrixClient);
          break;

        case 'set-mute':
          result = await setMute(matrixClient, action.params.muted);
          break;

        case 'toggle-deafen':
          result = await toggleDeafen(matrixClient);
          break;

        case 'set-deafen':
          result = await setDeafen(matrixClient, action.params.deafened);
          break;

        case 'change-channel':
          result = await changeChannel(matrixClient, action.params.roomId);
          break;

        case 'get-channels':
          result = await getChannels(matrixClient);
          break;

        case 'send-message':
          result = await sendMessage(matrixClient, action.params.roomId, action.params.message);
          break;

        case 'send-message-current':
          result = await sendMessageCurrent(matrixClient, action.params.message);
          break;

        case 'get-current-room':
          result = await getCurrentRoom(matrixClient);
          break;

        default:
          throw new Error(`Unknown action: ${action.action}`);
      }

      // Send success response back
      (window as any).electron.api.sendResponse(action.responseChannel, {
        success: true,
        data: result,
      });

      console.log('Paarrot API: Action completed successfully:', action.action);
    } catch (error: any) {
      console.error('Paarrot API: Action failed:', action.action, error);

      // Send error response back
      (window as any).electron.api.sendResponse(action.responseChannel, {
        success: false,
        error: error.message || 'Unknown error',
      });
    }
  });

  console.log('Paarrot API: Handler initialized');
}

/**
 * Get current app status
 */
async function getStatus(matrixClient: MatrixClient) {
  const currentRoom = getCurrentRoomId();
  
  // Get actual mute/deafen state from CallService if available
  const callService = getCallService();
  const activeCall = callService?.getActiveCall();
  
  return {
    muted: activeCall?.isMuted ?? false,
    deafened: activeCall?.isDeafened ?? false,
    currentRoom,
    connected: matrixClient.isInitialSyncComplete() || false,
    userId: matrixClient.getUserId(),
  };
}

/**
 * Toggle microphone mute
 */
async function toggleMute(matrixClient: MatrixClient) {
  const callService = getCallService();
  
  if (!callService) {
    return {
      muted: false,
      message: 'CallService not initialized - no active call',
    };
  }
  
  const activeCall = callService.getActiveCall();
  if (!activeCall) {
    return {
      muted: false,
      message: 'No active call to mute/unmute',
    };
  }
  
  // Toggle mute state
  const newMuteState = callService.toggleMute();
  
  return {
    muted: newMuteState,
  };
}

/**
 * Set microphone mute state
 */
async function setMute(matrixClient: MatrixClient, muted: boolean) {
  const callService = getCallService();
  
  if (!callService) {
    return {
      muted,
      message: 'CallService not initialized - no active call',
    };
  }
  
  const activeCall = callService.getActiveCall();
  if (!activeCall) {
    return {
      muted,
      message: 'No active call to mute/unmute',
    };
  }
  
  // Set mute to desired state if it's different
  if (activeCall.isMuted !== muted) {
    callService.toggleMute();
  }
  
  return {
    muted,
  };
}

/**
 * Toggle deafen (mute speakers)
 */
async function toggleDeafen(matrixClient: MatrixClient) {
  const callService = getCallService();
  
  if (!callService) {
    return {
      deafened: false,
      message: 'CallService not initialized - no active call',
    };
  }
  
  const activeCall = callService.getActiveCall();
  if (!activeCall) {
    return {
      deafened: false,
      message: 'No active call to deafen/undeafen',
    };
  }
  
  // Toggle deafen state
  const newDeafenState = callService.toggleDeafen();
  
  return {
    deafened: newDeafenState,
  };
}

/**
 * Set deafen state
 */
async function setDeafen(matrixClient: MatrixClient, deafened: boolean) {
  const callService = getCallService();
  
  if (!callService) {
    return {
      deafened,
      message: 'CallService not initialized - no active call',
    };
  }
  
  const activeCall = callService.getActiveCall();
  if (!activeCall) {
    return {
      deafened,
      message: 'No active call to deafen/undeafen',
    };
  }
  
  // Set deafen to desired state if it's different
  if (activeCall.isDeafened !== deafened) {
    callService.toggleDeafen();
  }
  
  return {
    deafened,
  };
}

/**
 * Change to a different room/channel
 */
async function changeChannel(matrixClient: any, roomId: string) {
  const room = matrixClient?.getRoom(roomId);
  if (!room) {
    throw new Error(`Room not found: ${roomId}`);
  }

  if (!navigateFunction) {
    throw new Error('Navigate function not registered. Call setPaarrotNavigate from your router setup.');
  }

  // Determine the appropriate path based on room type
  const roomIdOrAlias = getCanonicalAliasOrRoomId(matrixClient, roomId);
  let path: string;

  // Check if it's a direct message
  const isDirect = room.guessDMUserId() !== null;
  
  if (isDirect) {
    // Navigate to direct message
    path = getDirectRoomPath(roomIdOrAlias);
  } else if (isSpaceLikeRoom(room)) {
    // Navigate to space
    path = getSpaceRoomPath(roomIdOrAlias, roomIdOrAlias);
  } else {
    // Navigate to regular room in home
    path = getHomeRoomPath(roomIdOrAlias);
  }

  // Navigate to the room
  navigateFunction(path);

  return {
    roomId,
    roomName: room.name || 'Unnamed Room',
    path,
  };
}

/**
 * Get list of rooms/channels
 */
async function getChannels(matrixClient: any) {
  const rooms = matrixClient?.getRooms() || [];

  return rooms
    .filter((room: any) => !isSpaceLikeRoom(room))
    .map((room: any) => {
      // Extract server domain from roomId (!localpart:domain.tld)
      const serverMatch = room.roomId.match(/:(.+)$/);
      const server = serverMatch ? serverMatch[1] : null;
      
      return {
        roomId: room.roomId,
        name: room.name || 'Unnamed Room',
        server: server,
        isDirect: room.getMyMembership() === 'invite' ? false : room.guessDMUserId() !== null,
        avatar: room.getMxcAvatarUrl() || null,
      };
    })
    .sort((a: any, b: any) => a.name.localeCompare(b.name));
}

/**
 * Send a message to a specific room
 */
async function sendMessage(matrixClient: any, roomId: string, message: string) {
  const room = matrixClient?.getRoom(roomId);
  if (!room) {
    throw new Error(`Room not found: ${roomId}`);
  }

  const content = {
    msgtype: 'm.text',
    body: message.trim(),
  };

  const result = await matrixClient.sendMessage(roomId, content);

  return {
    eventId: result.event_id,
    roomId,
  };
}

/**
 * Send a message to the current room
 */
async function sendMessageCurrent(matrixClient: any, message: string) {
  const currentRoomId = getCurrentRoomId();
  if (!currentRoomId) {
    throw new Error('No room currently active');
  }

  return sendMessage(matrixClient, currentRoomId, message);
}

/**
 * Get information about the current room
 */
async function getCurrentRoom(matrixClient: any) {
  const currentRoomId = getCurrentRoomId();
  if (!currentRoomId) {
    throw new Error('No room currently active');
  }

  const room = matrixClient?.getRoom(currentRoomId);
  if (!room) {
    throw new Error(`Current room not found: ${currentRoomId}`);
  }

  // Extract server domain from roomId (!localpart:domain.tld)
  const serverMatch = room.roomId.match(/:(.+)$/);
  const server = serverMatch ? serverMatch[1] : null;

  return {
    roomId: room.roomId,
    name: room.name || 'Unnamed Room',
    server: server,
    avatar: room.getMxcAvatarUrl() || null,
    isDirect: room.guessDMUserId() !== null,
  };
}

/**
 * Get the currently active room ID
 * Extracts room ID from the current URL pathname
 */
function getCurrentRoomId(): string | null {
  try {
    // Get the pathname from URL
    // Support both normal routing and hash routing
    let pathname = window.location.pathname;
    
    // If using hash router, parse from hash
    if (window.location.hash) {
      const hashMatch = window.location.hash.match(/#(.+)/);
      if (hashMatch) {
        pathname = hashMatch[1];
      }
    }
    
    // URL patterns:
    // /home/:roomIdOrAlias/:eventId?/
    // /direct/:roomIdOrAlias/:eventId?/
    // /:spaceIdOrAlias/:roomIdOrAlias/:eventId?/
    
    // Try to match room patterns
    const patterns = [
      /^\/home\/([^/]+)/, // /home/:roomIdOrAlias
      /^\/direct\/([^/]+)/, // /direct/:roomIdOrAlias
      /^\/[^/]+\/([^/]+)/, // /:spaceIdOrAlias/:roomIdOrAlias (space rooms)
    ];
    
    for (const pattern of patterns) {
      const match = pathname.match(pattern);
      if (match && match[1]) {
        // Decode URI component in case the room ID was encoded
        return decodeURIComponent(match[1]);
      }
    }
    
    return null;
  } catch (error) {
    console.error('Paarrot API: Error getting current room ID:', error);
    return null;
  }
}

export default { initPaarrotAPI };
