/* eslint-disable react/destructuring-assignment */
import React, { MouseEventHandler, useState } from 'react';
import {
  Avatar,
  Box,
  Icon,
  IconButton,
  Icons,
  PopOut,
  RectCords,
  Text,
  Tooltip,
  TooltipProvider,
} from 'folds';
import FocusTrap from 'focus-trap-react';
import { useTranslation } from 'react-i18next';
import { useAtomValue } from 'jotai';
import { Room } from 'matrix-js-sdk';
import { PageHeader } from '../../components/page';
import { RoomAvatar, RoomIcon } from '../../components/room-avatar';
import { UserAvatar } from '../../components/user-avatar';
import { BackRouteHandler } from '../../components/BackRouteHandler';
import { ContainerColor } from '../../styles/ContainerColor.css';
import { ScreenSize, useScreenSizeContext } from '../../hooks/useScreenSize';
import { useStateEvent } from '../../hooks/useStateEvent';
import { useMatrixClient } from '../../hooks/useMatrixClient';
import { useMediaAuthentication } from '../../hooks/useMediaAuthentication';
import { useIsOneOnOne, useRoom } from '../../hooks/useRoom';
import { useDmCallVisible } from '../../hooks/useDmCallVisible';
import { useRoomMemberCount } from '../../hooks/useRoomMemberCount';
import { Presence, useUserPresence } from '../../hooks/useUserPresence';
import { useRoomAvatar, useRoomName } from '../../hooks/useRoomMeta';
import { useSpaceOptionally } from '../../hooks/useSpace';
import { useOpenRoomSettings } from '../../state/hooks/roomSettings';
import { useLivekitSupport } from '../../hooks/useLivekitSupport';
import { useCallMembers, useCallSession } from '../../hooks/useCall';
import { useSwitchOrStartDmCall } from '../../hooks/useSwitchOrStartDmCall';
import { useOpenUserRoomProfile } from '../../state/hooks/userRoomProfile';
import {
  useCloseRoomMembersSheet,
  useOpenRoomMembersSheet,
  useRoomMembersSheetState,
} from '../../state/hooks/roomMembersSheet';
import { callEmbedAtom } from '../../state/callEmbed';
import { RoomSettingsPage } from '../../state/roomSettings';
import { StateEvent } from '../../../types/matrix/room';
import {
  getMxIdLocalPart,
  getMxIdServer,
  guessDmRoomUserId,
  mxcUrlToHttp,
} from '../../utils/matrix';
import { stopPropagation } from '../../utils/keyboard';
import { useBotPresets } from '../bots/catalog';
import { isCatalogBotControlRoom } from '../bots/room';
import { RoomPinMenu } from './room-pin-menu';
import { RoomActionsMenu } from './room-actions';
import * as css from './RoomViewHeaderDm.css';

function DmCallButton({ room }: { room: Room }) {
  const { t } = useTranslation();
  const mx = useMatrixClient();
  const switchOrStartDmCall = useSwitchOrStartDmCall();
  const livekitSupported = useLivekitSupport();
  const session = useCallSession(room);
  const members = useCallMembers(room, session);
  const currentEmbed = useAtomValue(callEmbedAtom);

  const myUserId = mx.getSafeUserId();
  const inCallHere = currentEmbed?.roomId === room.roomId;
  if (inCallHere) return null;

  const ongoingByOthers = members.length > 0 && !members.some((m) => m.userId === myUserId);
  const disabled = !livekitSupported;
  let tooltipText: string;
  if (!livekitSupported) tooltipText = t('Call.unavailable');
  else if (ongoingByOthers) tooltipText = t('Call.join');
  else tooltipText = t('Call.start');

  const handleClick = () => {
    if (disabled) return;
    switchOrStartDmCall(room.roomId).catch((err: unknown) => {
      // eslint-disable-next-line no-console
      console.warn('[call] header switch/start failed', err);
    });
  };

  return (
    <TooltipProvider
      position="Bottom"
      offset={4}
      tooltip={
        <Tooltip>
          <Text>{tooltipText}</Text>
        </Tooltip>
      }
    >
      {(triggerRef) => (
        <IconButton
          fill="None"
          ref={triggerRef}
          onClick={handleClick}
          disabled={disabled}
          aria-label={tooltipText}
        >
          <Icon size="400" src={Icons.Phone} />
        </IconButton>
      )}
    </TooltipProvider>
  );
}

export function RoomViewHeaderDm({ callView }: { callView?: boolean }) {
  const { t } = useTranslation();
  const mx = useMatrixClient();
  const useAuthentication = useMediaAuthentication();
  const screenSize = useScreenSizeContext();
  const room = useRoom();
  const isOneOnOne = useIsOneOnOne();
  const isMobile = screenSize === ScreenSize.Mobile;

  // Call surface visibility is shared with the `Call` button inside
  // `UserRoomProfile` via `useDmCallVisible` — the hook captures all
  // four gates (1:1 + m.direct + !bridged + !bot-control) so the two
  // call-entry surfaces can't drift apart. Header-specific extras
  // here: hide in callView (we're already showing CallView). The
  // hook itself documents the call-lifecycle reasoning.
  const dmCallVisible = useDmCallVisible(room);
  const callButtonVisible = !callView && dmCallVisible;

  // `isBotControlRoom` is also passed down to `RoomMenu` to gate the
  // bot-config menu item — kept here as its own derivation because
  // the hook above is purpose-built for the call gate, not for
  // generic «is this a bot DM?» queries.
  const bots = useBotPresets();
  const isBotControlRoom = isCatalogBotControlRoom(mx, room, bots);

  const encryptionEvent = useStateEvent(room, StateEvent.RoomEncryption);
  const encryptedRoom = !!encryptionEvent;

  const avatarMxc = useRoomAvatar(room, isOneOnOne);
  const name = useRoomName(room);
  const memberCount = useRoomMemberCount(room);
  const avatarUrl = avatarMxc
    ? mxcUrlToHttp(mx, avatarMxc, useAuthentication, 96, 96, 'crop') ?? undefined
    : undefined;

  // Peer details for 1:1 chrome — handle (`local:server`, no `@` prefix —
  // we drop the sigil to keep the line lighter) and tap-to-open user-room-
  // profile sheet. `guessDmRoomUserId` returns the oldest-joined non-self
  // member, but its last fallback is `myUserId` itself — drop that case so
  // we never render the room as if I were the peer (avatar trigger would
  // open my own profile, handle would show my mxid).
  //
  // The server segment is kept so cross-server users with identical
  // local-parts (e.g. `alex:vojo.chat` vs `alex:other.org`) stay visually
  // distinct.
  const myUserId = mx.getSafeUserId();
  const peerCandidate = isOneOnOne ? guessDmRoomUserId(room, myUserId) : undefined;
  const peerUserId = peerCandidate && peerCandidate !== myUserId ? peerCandidate : undefined;
  const peerLocal = peerUserId ? getMxIdLocalPart(peerUserId) : undefined;
  const peerServer = peerUserId ? getMxIdServer(peerUserId) : undefined;
  const handle =
    peerLocal && peerServer ? `${peerLocal}:${peerServer}` : peerUserId?.replace(/^@/, '');

  // `useUserPresence` is a no-op when `peerUserId` is undefined (group rooms,
  // unresolved peer) — it just returns undefined. Real presence comes from
  // matrix-js-sdk `User` events; the hook subscribes to Presence /
  // CurrentlyActive / LastPresenceTs and re-renders. We only show «в сети»
  // when the peer is actively online; offline / unavailable hides the line.
  const peerPresence = useUserPresence(peerUserId ?? '');
  const peerOnline = !!peerUserId && peerPresence?.presence === Presence.Online;

  const [menuAnchor, setMenuAnchor] = useState<RectCords>();
  const [pinMenuAnchor, setPinMenuAnchor] = useState<RectCords>();
  const openUserRoomProfile = useOpenUserRoomProfile();
  const openRoomMembersSheet = useOpenRoomMembersSheet();
  const closeRoomMembersSheet = useCloseRoomMembersSheet();
  const membersSheetState = useRoomMembersSheetState();
  const membersSheetOpen = membersSheetState?.roomId === room.roomId;
  const parentSpace = useSpaceOptionally();
  const openSettings = useOpenRoomSettings();

  // The ⋮ overflow opens the RoomActionsMenu in an anchored PopOut — same
  // chrome on desktop and mobile.
  const handleOpenMenu: MouseEventHandler<HTMLButtonElement> = (evt) => {
    setMenuAnchor(evt.currentTarget.getBoundingClientRect());
  };
  const handlePeerProfile: MouseEventHandler<HTMLButtonElement> = (evt) => {
    if (!peerUserId) return;
    openUserRoomProfile(
      room.roomId,
      parentSpace?.roomId,
      peerUserId,
      evt.currentTarget.getBoundingClientRect(),
      'Bottom'
    );
  };
  const handleGroupIdentityClick = () => {
    if (membersSheetOpen) {
      closeRoomMembersSheet();
    } else {
      openRoomMembersSheet(room.roomId);
    }
  };
  // `callView` keeps the legacy «open Members in Settings» fallback —
  // the members side-pane isn't mounted while we're inside the call
  // surface, so a separate path is still needed to reach the list.
  const handleCallViewMembers = () => {
    openSettings(room.roomId, parentSpace?.roomId, RoomSettingsPage.MembersPage);
  };

  const avatarNode = (
    <Avatar size="300">
      {isOneOnOne && peerUserId ? (
        <UserAvatar
          userId={peerUserId}
          src={avatarUrl}
          alt={name}
          renderFallback={() => <Icon size="200" src={Icons.User} filled />}
        />
      ) : (
        <RoomAvatar
          roomId={room.roomId}
          src={avatarUrl}
          alt={name}
          renderFallback={() => (
            <RoomIcon size="200" joinRule={room.getJoinRule()} roomType={room.getType()} />
          )}
        />
      )}
    </Avatar>
  );

  const e2eeChip = encryptedRoom && (
    <Text as="span" size="T200" className={css.E2eeChip}>
      <Icon src={Icons.Lock} filled className={css.E2eeIcon} />
      {t('Room.encrypted_short')}
    </Text>
  );

  // Single subline format, identical on mobile + desktop:
  //   1:1   →  «@local:server» (mono) + (peer online ? « · в сети» : nothing)
  //   group →  «N members»
  // Title row carries the room name and the «онлайн» presence tag (1:1
  // peer only, when actually Online via `useUserPresence`). Subline carries
  // the muted identifier (handle for 1:1, member-count for groups) and,
  // for 1:1 rooms, the e2ee chip — moved out of the title row so the chip
  // sits near the technical identifier rather than the human name.
  const showOnlineTag = isOneOnOne && peerOnline;
  const showHandlePart = isOneOnOne && !!handle;
  const showGroupSubline = !isOneOnOne;

  // Title block (name row + subline) — identical for 1:1 and group; the
  // difference is purely in the wrapper (clickable identity button for
  // 1:1, plain row for groups).
  const titleBlock = (
    <Box grow="Yes" direction="Column" style={{ minWidth: 0 }}>
      <div className={css.TitleRow}>
        <Text size={isMobile ? 'H5' : 'H4'} truncate className={css.RoomName}>
          {name}
        </Text>
        {showOnlineTag && (
          <Text as="span" size="T200" className={css.OnlineTag}>
            {t('Room.status_online')}
          </Text>
        )}
      </div>
      {showHandlePart && (
        <Text as="span" size="T200" className={css.Subline}>
          <span className={css.SublineMuted}>{handle}</span>
          {e2eeChip}
        </Text>
      )}
      {showGroupSubline && (
        <Text as="span" size="T200" className={css.Subline}>
          <span className={css.SublineMuted}>
            {t('Room.members_count', {
              count: memberCount,
              formattedCount: memberCount,
            })}
          </span>
          {e2eeChip}
        </Text>
      )}
    </Box>
  );

  // For 1:1 rooms wrap the avatar AND title in a single button so a tap
  // anywhere on the user identity (avatar, name, handle, online tag)
  // opens the user-room-profile sheet — one tab stop, one focus
  // outline, single popout anchor. For group rooms the same button
  // pattern opens the members sheet instead — keeps the gesture
  // language symmetrical across 1:1 and group. `callView` falls back
  // to a static row because neither sheet is reachable inside the
  // call surface.
  let identityArea: React.ReactNode;
  if (isOneOnOne && peerUserId) {
    identityArea = (
      <button
        type="button"
        className={css.PeerIdentityTrigger}
        onClick={handlePeerProfile}
        aria-label={t('Room.open_profile_of', { name })}
      >
        {avatarNode}
        {titleBlock}
      </button>
    );
  } else if (!isOneOnOne && !callView) {
    identityArea = (
      <button
        type="button"
        className={css.PeerIdentityTrigger}
        onClick={handleGroupIdentityClick}
        aria-pressed={membersSheetOpen}
        aria-label={t('Room.open_members_of', { name })}
      >
        {avatarNode}
        {titleBlock}
      </button>
    );
  } else {
    identityArea = (
      <>
        <span className={css.PeerAvatarStatic}>{avatarNode}</span>
        {titleBlock}
      </>
    );
  }

  return (
    <PageHeader
      className={`${ContainerColor({ variant: 'SurfaceVariant' })} ${css.HeaderShell}`}
      balance={isMobile}
    >
      {/* `gap="200"` (= S200 = 8px) keeps the avatar's right side flush with
          the same `S200` left/top/bottom clearance the header gives — using
          the default `gap="300"` (12px) made the avatar→title spacing
          visibly looser than the rest of its surround. */}
      <Box grow="Yes" alignItems="Center" gap="200">
        {isMobile && (
          <BackRouteHandler>
            {(onBack) => (
              <Box shrink="No" alignItems="Center">
                <IconButton fill="None" onClick={onBack} aria-label={t('Room.close')}>
                  <Icon src={Icons.ChevronLeft} />
                </IconButton>
              </Box>
            )}
          </BackRouteHandler>
        )}

        {identityArea}

        <Box shrink="No" alignItems="Center">
          {callButtonVisible && <DmCallButton room={room} />}

          {/* Member toggle — kept only for `callView` (1:1 or group): the
              members side-pane / horseshoe isn't mounted under the call
              surface, so we still need a way to reach the member list
              via Room Settings → Members. Non-call group rooms now use
              the identity button above (tap on avatar+title) — keeps
              the gesture symmetrical with 1:1 peer profile. */}
          {callView && screenSize === ScreenSize.Desktop && (
            <TooltipProvider
              position="Bottom"
              offset={4}
              tooltip={
                <Tooltip>
                  <Text>{t('Room.members')}</Text>
                </Tooltip>
              }
            >
              {(triggerRef) => (
                <IconButton fill="None" ref={triggerRef} onClick={handleCallViewMembers}>
                  <Icon size="400" src={Icons.User} />
                </IconButton>
              )}
            </TooltipProvider>
          )}

          <TooltipProvider
            position="Bottom"
            align="End"
            offset={4}
            tooltip={
              <Tooltip>
                <Text>{t('Room.more_options')}</Text>
              </Tooltip>
            }
          >
            {(triggerRef) => (
              <IconButton
                fill="None"
                onClick={handleOpenMenu}
                ref={triggerRef}
                aria-pressed={!!menuAnchor}
              >
                <Icon size="400" src={Icons.VerticalDots} filled={!!menuAnchor} />
              </IconButton>
            )}
          </TooltipProvider>

          <PopOut
            anchor={menuAnchor}
            position="Bottom"
            align="End"
            content={
              <FocusTrap
                focusTrapOptions={{
                  initialFocus: false,
                  returnFocusOnDeactivate: false,
                  onDeactivate: () => setMenuAnchor(undefined),
                  clickOutsideDeactivates: true,
                  isKeyForward: (evt: KeyboardEvent) => evt.key === 'ArrowDown',
                  isKeyBackward: (evt: KeyboardEvent) => evt.key === 'ArrowUp',
                  escapeDeactivates: stopPropagation,
                }}
              >
                <RoomActionsMenu
                  room={room}
                  callView={callView}
                  botControlRoom={isBotControlRoom}
                  onPin={(cords) => setPinMenuAnchor(cords)}
                  requestClose={() => setMenuAnchor(undefined)}
                />
              </FocusTrap>
            }
          />

          <PopOut
            anchor={pinMenuAnchor}
            position="Bottom"
            align="End"
            content={
              <FocusTrap
                focusTrapOptions={{
                  initialFocus: false,
                  returnFocusOnDeactivate: false,
                  onDeactivate: () => setPinMenuAnchor(undefined),
                  clickOutsideDeactivates: true,
                  isKeyForward: (evt: KeyboardEvent) => evt.key === 'ArrowDown',
                  isKeyBackward: (evt: KeyboardEvent) => evt.key === 'ArrowUp',
                  escapeDeactivates: stopPropagation,
                }}
              >
                <RoomPinMenu room={room} requestClose={() => setPinMenuAnchor(undefined)} />
              </FocusTrap>
            }
          />
        </Box>
      </Box>
    </PageHeader>
  );
}
