import { useCallback, useEffect } from 'react';
import { useNavigate } from 'react-router';
import { useMatrixClient } from './useMatrixClient';
import { useRoomNavigate } from './useRoomNavigate';
import { isRoomId } from '../utils/matrix';
import { getHomeRoomPath, withSearchParam } from '../pages/pathUtils';
import { _RoomSearchParams } from '../pages/paths';
import { parseMatrixToRoom, parseMatrixToRoomEvent, testMatrixTo } from '../plugins/matrix-to';

/** Desktop (Tauri) injects deep links via a DOM CustomEvent — see lib.rs. */
const DEEP_LINK_EVENT = 'lotus-deeplink';

const inTauri = (): boolean => '__TAURI_INTERNALS__' in window;

const tryDecode = (value: string): string => {
  try {
    return decodeURIComponent(value);
  } catch {
    return value;
  }
};

/**
 * Convert a `matrix:` URI (MSC2312) to its `matrix.to` equivalent so we can
 * reuse the existing matrix.to parsers. Returns undefined for forms we don't
 * route (e.g. user links, which need an anchor/room context to open a profile).
 *
 *   matrix:r/room:server          -> https://matrix.to/#/#room:server
 *   matrix:roomid/id:server/e/$ev -> https://matrix.to/#/!id:server/$ev
 */
const matrixUriToMatrixTo = (uri: string): string | undefined => {
  const body = uri.slice('matrix:'.length);
  const [pathPart, queryPart] = body.split('?');
  const segments = pathPart.split('/');
  if (segments.length < 2) return undefined;

  const [kind, rawId, evKind, rawEventId] = segments;
  const sigil = kind === 'r' ? '#' : kind === 'roomid' ? '!' : undefined;
  if (!sigil || !rawId) return undefined;

  let fragment = `${sigil}${tryDecode(rawId)}`;
  if (evKind === 'e' && rawEventId) {
    fragment += `/$${tryDecode(rawEventId)}`;
  }
  const query = queryPart ? `?${queryPart}` : '';
  return `https://matrix.to/#/${fragment}${query}`;
};

/**
 * Routes deep links opened from outside the app (Windows `matrix:` links,
 * forwarded from Tauri) into the client, mirroring the navigation in
 * useMentionClickHandler. No-op outside Tauri.
 */
export const useDeepLinkNavigate = (): void => {
  const mx = useMatrixClient();
  const navigate = useNavigate();
  const { navigateRoom, navigateSpace } = useRoomNavigate();

  const navigateUri = useCallback(
    (rawUrl: string) => {
      const href = rawUrl.startsWith('matrix:') ? matrixUriToMatrixTo(rawUrl) : rawUrl;
      if (!href || !testMatrixTo(href)) return;

      const roomEvent = parseMatrixToRoomEvent(href);
      const target = roomEvent ?? parseMatrixToRoom(href);
      if (!target) return; // users / unsupported forms

      const { roomIdOrAlias, viaServers } = target;
      const eventId = roomEvent?.eventId;

      // Already-joined room/space: navigate directly.
      if (isRoomId(roomIdOrAlias) && mx.getRoom(roomIdOrAlias)) {
        if (mx.getRoom(roomIdOrAlias)?.isSpaceRoom()) navigateSpace(roomIdOrAlias);
        else navigateRoom(roomIdOrAlias, eventId);
        return;
      }

      // Otherwise route through the home path (triggers the join/preview flow).
      const path = getHomeRoomPath(roomIdOrAlias, eventId);
      navigate(
        viaServers && viaServers.length > 0
          ? withSearchParam<_RoomSearchParams>(path, { viaServers: viaServers.join(',') })
          : path,
      );
    },
    [mx, navigate, navigateRoom, navigateSpace],
  );

  useEffect(() => {
    if (!inTauri()) return undefined;
    const handler = (evt: Event) => {
      const { detail } = evt as CustomEvent<unknown>;
      if (typeof detail === 'string') navigateUri(detail);
    };
    window.addEventListener(DEEP_LINK_EVENT, handler);
    return () => window.removeEventListener(DEEP_LINK_EVENT, handler);
  }, [navigateUri]);
};
