import React, { useCallback } from 'react';
import { Box, Line, toRem } from 'folds';
import { useMatch, useParams } from 'react-router-dom';
import { isKeyHotkey } from 'is-hotkey';
import { useAtomValue } from 'jotai';
import { RoomView } from './RoomView';
import { userRoomProfileAtom } from '../../state/userRoomProfile';
import { ContainerColor } from '../../styles/ContainerColor.css';
import { VOJO_HORSESHOE_GAP_PX, VOJO_HORSESHOE_VOID_COLOR } from '../../styles/horseshoe';
import { MembersDrawer } from './MembersDrawer';
import { ThreadDrawer } from './ThreadDrawer';
import { ScreenSize, useScreenSizeContext } from '../../hooks/useScreenSize';
import { useSetting } from '../../state/hooks/settings';
import { settingsAtom } from '../../state/settings';
import { PowerLevelsContextProvider, usePowerLevels } from '../../hooks/usePowerLevels';
import { useIsOneOnOne, useRoom } from '../../hooks/useRoom';
import { useKeyDown } from '../../hooks/useKeyDown';
import { markAsRead } from '../../utils/notifications';
import { useMatrixClient } from '../../hooks/useMatrixClient';
import { useRoomMembers } from '../../hooks/useRoomMembers';
import { CallView } from '../call/CallView';
import { RoomViewHeader } from './RoomViewHeader';
import { callChatAtom } from '../../state/callEmbed';
import { CallChatView } from './CallChatView';
import { RoomViewProfilePanel } from './RoomViewProfilePanel';
import { RoomViewProfileSidePanel } from './RoomViewProfileSidePanel';
import { useChannelsMode, ThreadDrawerOpenProvider } from '../../hooks/useChannelsMode';
import { CHANNELS_THREAD_PATH } from '../../pages/paths';
import { getChannelsRoomPath } from '../../pages/pathUtils';
import { isBridgedRoom } from '../../utils/room';
import { useUnreadThreadingEnabled } from '../../hooks/useClientConfig';

type RoomProps = {
  renderRoomView?: (props: { eventId?: string }) => React.ReactNode;
};

export function Room({ renderRoomView }: RoomProps) {
  const { eventId } = useParams();
  const room = useRoom();
  const mx = useMatrixClient();
  const channelsMode = useChannelsMode();
  // Match the thread URL pattern via useMatch rather than reading
  // useParams: rootId lives in a CHILD route relative to <Room>, so
  // useParams here returns only the room-level segments. useMatch
  // walks the absolute URL and gives us all four segments back.
  const threadMatch = useMatch({ path: CHANNELS_THREAD_PATH, end: true });
  const matchedSpaceParam = threadMatch?.params.spaceIdOrAlias;
  const matchedRoomParam = threadMatch?.params.roomIdOrAlias;
  const matchedRootParam = threadMatch?.params.rootId;
  // Suppress the drawer in bridged rooms. Telegram puppets have no
  // m.thread on the bridge side; M7 will replace this gate with an
  // inline-quote indicator. Until then, keeping the drawer hidden
  // matches the «Reply in Thread» button gate in RoomTimeline.
  const showThreadDrawer =
    channelsMode &&
    !!matchedRootParam &&
    !!matchedSpaceParam &&
    !!matchedRoomParam &&
    !isBridgedRoom(room);
  let parentRoomPath: string | undefined;
  let decodedRootId: string | undefined;
  if (showThreadDrawer && matchedSpaceParam && matchedRoomParam && matchedRootParam) {
    try {
      parentRoomPath = getChannelsRoomPath(
        decodeURIComponent(matchedSpaceParam),
        decodeURIComponent(matchedRoomParam)
      );
    } catch {
      parentRoomPath = getChannelsRoomPath(matchedSpaceParam, matchedRoomParam);
    }
    try {
      decodedRootId = decodeURIComponent(matchedRootParam);
    } catch {
      decodedRootId = matchedRootParam;
    }
  }
  const [isDrawer] = useSetting(settingsAtom, 'isPeopleDrawer');
  const [hideActivity] = useSetting(settingsAtom, 'hideActivity');
  const screenSize = useScreenSizeContext();
  const isMobile = screenSize === ScreenSize.Mobile;
  // Mobile drawer takes over the chat column instead of sitting beside
  // it — the timeline+composer stay mounted but visually hidden, so the
  // M5 nav-stack work picks up where M2 left off without re-routing.
  const drawerHidesChat = showThreadDrawer && isMobile;
  const powerLevels = usePowerLevels(room);
  const members = useRoomMembers(mx, room.roomId);
  const chat = useAtomValue(callChatAtom);
  // 1:1 rooms get peer-profile-sheet via avatar tap in the header instead of
  // the members drawer — see dm_1x1_redesign.md §8 P4 deliverable 9. The
  // value comes from the same `IsOneOnOneProvider` the header reads, so the
  // drawer-suppression and header chrome flip together when membership
  // changes (provider is reactive via `useIsOneOnOneRoom` upstream).
  const isOneOnOne = useIsOneOnOne();

  const unreadThreadingEnabled = useUnreadThreadingEnabled();

  // Profile horseshoe: when the right-side profile pane is open on
  // desktop/tablet, paint a 12px void seam between the chat column and
  // the profile, and carve rounded TL/BL corners on the profile pane.
  // The chat column itself keeps a straight right edge (no rounding) —
  // only the profile carves, so the void gap reads as one black bar
  // with a single rounded contour on the right side of the seam.
  // Mirrors the page-nav <-> chat split from PageRoot (commit 363bd9d)
  // minus the chat-side rounding. Mobile and the thread-drawer case
  // don't mount the side pane, so the wrap is gated on both.
  //
  // Void colour is painted on the parent flex row (covering everything
  // not painted by an opaque child) so the profile pane's TL/BL carves
  // expose void rather than the chat-panel-inner's Background from
  // PageRoot. The chat column applies an explicit Background bg so the
  // parent void can't bleed through any transparent slivers.
  const profileOpen = !!useAtomValue(userRoomProfileAtom);
  const showProfileHorseshoe = profileOpen && !isMobile && !showThreadDrawer;

  useKeyDown(
    window,
    useCallback(
      (evt) => {
        // Escape marks the room as read. Pre-M4 the receipt handler
        // blind-deleted ALL room unread on any own receipt, so the
        // drawer-open case had to be skipped to avoid wiping thread
        // unread the user hadn't seen. After the M4 receipt-handler
        // refactor (PUT-with-fresh, partitioned by thread_id) main and
        // thread unread are independent, so Escape on the channel main
        // surface marks main as read and leaves threads alone — works
        // unconditionally. Under the kill switch the handler reverts
        // to blind DELETE, so we keep the drawer-open guard there.
        if (
          isKeyHotkey('escape', evt) &&
          (unreadThreadingEnabled || !showThreadDrawer)
        ) {
          markAsRead(mx, room.roomId, hideActivity);
        }
      },
      [mx, room.roomId, hideActivity, showThreadDrawer, unreadThreadingEnabled]
    )
  );

  const callView = room.isCallRoom();

  return (
    <PowerLevelsContextProvider value={powerLevels}>
      <ThreadDrawerOpenProvider value={showThreadDrawer}>
        <Box
          grow="Yes"
          style={
            showProfileHorseshoe
              ? { backgroundColor: VOJO_HORSESHOE_VOID_COLOR }
              : undefined
          }
        >
          {callView && (screenSize === ScreenSize.Desktop || !chat) && (
            <Box
              grow="Yes"
              direction="Column"
              className={
                showProfileHorseshoe ? ContainerColor({ variant: 'Background' }) : undefined
              }
            >
              <RoomViewProfilePanel header={<RoomViewHeader callView />}>
                <Box grow="Yes">
                  <CallView />
                </Box>
              </RoomViewProfilePanel>
            </Box>
          )}
          {!callView && !drawerHidesChat && (
            <Box
              grow="Yes"
              direction="Column"
              className={
                showProfileHorseshoe ? ContainerColor({ variant: 'Background' }) : undefined
              }
            >
              <RoomViewProfilePanel header={<RoomViewHeader />}>
                <Box grow="Yes">
                  {renderRoomView?.({ eventId }) ?? <RoomView eventId={eventId} />}
                </Box>
              </RoomViewProfilePanel>
            </Box>
          )}

        {/* Tablet / Desktop: profile renders as a third pane to the
            right of the chat. Mobile uses the top horseshoe inside
              `RoomViewProfilePanel`, so we don't mount the side pane
              there. The 12px void gap (same as page-nav <-> chat split
              from PageRoot) sits between the chat column and the pane
              so the seam reads identically to the rest of the app. */}
          {!isMobile && !showThreadDrawer && (
            <>
              {showProfileHorseshoe && (
                <Box
                  shrink="No"
                  style={{
                    width: toRem(VOJO_HORSESHOE_GAP_PX),
                    backgroundColor: VOJO_HORSESHOE_VOID_COLOR,
                  }}
                />
              )}
              <RoomViewProfileSidePanel />
            </>
          )}

          {callView && chat && (
            <>
              {screenSize === ScreenSize.Desktop && (
                <Line variant="Background" direction="Vertical" size="300" />
              )}
              <CallChatView />
            </>
          )}
          {/* Members drawer hidden when thread drawer is open — three
              simultaneous side panes don't fit the chat column on
              anything narrower than ultrawide. The thread is the more
              recent intent so it wins. */}
          {!callView &&
            !isOneOnOne &&
            !showThreadDrawer &&
            screenSize === ScreenSize.Desktop &&
            isDrawer && (
              <>
                <Line variant="Background" direction="Vertical" size="300" />
                <MembersDrawer key={room.roomId} room={room} members={members} />
              </>
            )}
          {showThreadDrawer && decodedRootId && parentRoomPath && (
            <ThreadDrawer
              key={`${room.roomId}/${decodedRootId}`}
              room={room}
              rootId={decodedRootId}
              parentRoomPath={parentRoomPath}
              variant={isMobile ? 'mobile' : 'desktop'}
            />
          )}
        </Box>
      </ThreadDrawerOpenProvider>
    </PowerLevelsContextProvider>
  );
}
