// Action surfaces rendered alongside the user-profile card after
// the Dawn redesign:
//
//   - `UserActionsMenu` — single 3-dot pill anchored to the
//     top-right of the card. Hosts every imperative action we have
//     (start DM in groups, block / unblock, kick / ban / invite for
//     mods). Replaces the old bottom actions row, which on mobile
//     overflowed past the rail height — the user couldn't reach
//     Block without discovering a hidden scroll.
//   - `IgnoredUserAlert` — banner shown when the viewer has the
//     profile target on their ignore list. Pure information, no
//     action of its own.
//
// The legacy chip-strip components (Server / Share / MutualRooms)
// were lifted into `UserInfoRows.tsx` as Fleet-style attribute rows
// and are intentionally not re-exported here.

import React, { MouseEventHandler, useCallback, useState } from 'react';
import FocusTrap from 'focus-trap-react';
import { isKeyHotkey } from 'is-hotkey';
import {
  Box,
  Icon,
  IconButton,
  Icons,
  Line,
  Menu,
  MenuItem,
  PopOut,
  RectCords,
  Spinner,
  Text,
  config,
  toRem,
} from 'folds';
import { useTranslation } from 'react-i18next';
import { useMatrixClient } from '../../hooks/useMatrixClient';
import { stopPropagation } from '../../utils/keyboard';
import { AsyncStatus, useAsyncCallback } from '../../hooks/useAsyncCallback';
import { useIgnoredUsers } from '../../hooks/useIgnoredUsers';
import { CutoutCard } from '../cutout-card';
import { SettingTile } from '../setting-tile';
import { UserModeration } from './UserModeration';

export function IgnoredUserAlert() {
  const { t } = useTranslation();
  return (
    <CutoutCard style={{ padding: config.space.S200 }} variant="Critical">
      <SettingTile>
        <Box direction="Column" gap="200">
          <Box gap="200" justifyContent="SpaceBetween">
            <Text size="L400">{t('User.blocked_title')}</Text>
          </Box>
          <Box direction="Column">
            <Text size="T200">{t('User.blocked_description')}</Text>
          </Box>
        </Box>
      </SettingTile>
    </CutoutCard>
  );
}

type UserActionsMenuProps = {
  userId: string;
  // Whether to surface «Написать» (start a private DM) — true only
  // in group rooms when the target isn't the viewer themselves; in
  // 1:1 the user is already in the conversation, so the action is a
  // no-op.
  showStartDm?: boolean;
  onStartDm?: () => void;
  // Room-moderation gates. Each is independently true/false; if all
  // three are false the moderation block is suppressed entirely so
  // the menu doesn't carry a dangling separator.
  canKick?: boolean;
  canBan?: boolean;
  canInvite?: boolean;
};

// 3-dot pill containing every imperative action for the profile
// target. Anchored top-right of the card by the parent layout.
//
// Block / Unblock lives here too — earlier I tried promoting it to
// a standalone chip in a bottom actions row, but on mobile the rail
// is ~42vh and that row scrolled below the visible rail edge, so
// users couldn't reach it. Putting Block back into the menu keeps
// the action accessible at the same vertical position regardless of
// content length.
export function UserActionsMenu({
  userId,
  showStartDm,
  onStartDm,
  canKick,
  canBan,
  canInvite,
}: UserActionsMenuProps) {
  const { t } = useTranslation();
  const mx = useMatrixClient();
  const [cords, setCords] = useState<RectCords>();

  const open: MouseEventHandler<HTMLButtonElement> = (evt) => {
    // Anchor the popout to the trigger's TOP edge with zero height
    // — `position="Bottom"` then drops the menu starting from that
    // edge, so it visually covers the 3-dot button instead of
    // floating below it. Looks tighter on mobile where space is
    // tight; the trigger naturally re-emerges when the menu closes.
    const rect = evt.currentTarget.getBoundingClientRect();
    setCords({ x: rect.x, y: rect.y, width: rect.width, height: 0 });
  };
  const close = () => setCords(undefined);

  const ignoredUsers = useIgnoredUsers();
  const ignored = ignoredUsers.includes(userId);

  const [ignoreState, toggleIgnore] = useAsyncCallback(
    useCallback(async () => {
      const next = ignoredUsers.filter((u) => u !== userId);
      if (!ignored) next.push(userId);
      await mx.setIgnoredUsers(next);
    }, [mx, ignoredUsers, userId, ignored])
  );
  const ignoring = ignoreState.status === AsyncStatus.Loading;

  const moderationVisible = !!(canKick || canBan || canInvite);

  return (
    <PopOut
      anchor={cords}
      position="Bottom"
      align="End"
      // No offset: combined with the `height: 0` anchor above, this
      // makes the popout's top edge land on the trigger's top edge
      // — i.e., the menu opens *over* the 3-dots, not below.
      offset={0}
      content={
        <FocusTrap
          focusTrapOptions={{
            initialFocus: false,
            onDeactivate: close,
            clickOutsideDeactivates: true,
            escapeDeactivates: stopPropagation,
            isKeyForward: (evt: KeyboardEvent) => isKeyHotkey('arrowdown', evt),
            isKeyBackward: (evt: KeyboardEvent) => isKeyHotkey('arrowup', evt),
          }}
        >
          <Menu style={{ minWidth: toRem(220) }}>
            {showStartDm && onStartDm && (
              <div style={{ padding: config.space.S100 }}>
                <MenuItem
                  variant="Surface"
                  fill="None"
                  size="300"
                  radii="300"
                  onClick={() => {
                    onStartDm();
                    close();
                  }}
                  before={<Icon size="50" src={Icons.Message} filled />}
                >
                  <Text size="B300">{t('User.message')}</Text>
                </MenuItem>
              </div>
            )}
            {showStartDm && onStartDm && <Line size="300" />}
            <div style={{ padding: config.space.S100 }}>
              <MenuItem
                variant="Critical"
                fill="None"
                size="300"
                radii="300"
                onClick={() => {
                  toggleIgnore();
                  close();
                }}
                before={
                  ignoring ? (
                    <Spinner variant="Critical" size="50" />
                  ) : (
                    <Icon size="50" src={Icons.Prohibited} />
                  )
                }
                disabled={ignoring}
              >
                <Text size="B300">{ignored ? t('User.unblock') : t('User.block')}</Text>
              </MenuItem>
            </div>
            {moderationVisible && (
              <>
                <Line size="300" />
                <div style={{ padding: config.space.S200 }}>
                  <UserModeration
                    userId={userId}
                    canKick={!!canKick}
                    canBan={!!canBan}
                    canInvite={!!canInvite}
                  />
                </div>
              </>
            )}
          </Menu>
        </FocusTrap>
      }
    >
      <IconButton
        size="300"
        radii="Pill"
        fill="None"
        onClick={open}
        aria-pressed={!!cords}
        aria-label={t('User.more')}
      >
        <Icon size="200" src={Icons.VerticalDots} />
      </IconButton>
    </PopOut>
  );
}
