import React, { ChangeEvent, useCallback, useMemo, useRef, useState } from 'react';
import FocusTrap from 'focus-trap-react';
import {
  Avatar,
  Box,
  Button,
  Checkbox,
  color,
  config,
  Header,
  Icon,
  IconButton,
  Icons,
  Input,
  Line,
  MenuItem,
  Modal,
  Overlay,
  OverlayBackdrop,
  OverlayCenter,
  Scroll,
  Spinner,
  Text,
} from 'folds';
import { MatrixEvent, Room } from 'matrix-js-sdk';
import { useAtomValue } from 'jotai';
import { useMatrixClient } from '../../../hooks/useMatrixClient';
import { stopPropagation } from '../../../utils/keyboard';
import { useModalStyle } from '../../../hooks/useModalStyle';
import { mDirectAtom } from '../../../state/mDirectList';
import { useMediaAuthentication } from '../../../hooks/useMediaAuthentication';
import { mxcUrlToHttp } from '../../../utils/matrix';
import { RoomAvatar, RoomIcon } from '../../../components/room-avatar';
import { buildForwardContent } from './forwardContent';

type RoomRowProps = {
  room: Room;
  dm: boolean;
  useAuthentication: boolean;
  selected: boolean;
  onToggle: () => void;
  sending: boolean;
};
function RoomRow({ room, dm, useAuthentication, selected, onToggle, sending }: RoomRowProps) {
  const mx = useMatrixClient();
  const avatarMxc = room.getMxcAvatarUrl();
  const avatarUrl = avatarMxc
    ? (mxcUrlToHttp(mx, avatarMxc, useAuthentication, 48, 48, 'crop') ?? undefined)
    : undefined;

  return (
    <MenuItem
      size="300"
      radii="300"
      onClick={onToggle}
      disabled={sending}
      after={
        <Checkbox
          checked={selected}
          readOnly
          variant="Primary"
          disabled={sending}
          onClick={(evt) => {
            evt.stopPropagation();
            onToggle();
          }}
        />
      }
      before={
        <Avatar size="200" radii="300">
          <RoomAvatar
            roomId={room.roomId}
            src={avatarUrl}
            alt={room.name}
            renderFallback={() => (
              <RoomIcon roomType={room.getType()} size="100" joinRule={room.getJoinRule()} filled />
            )}
          />
        </Avatar>
      }
    >
      <Box direction="Column">
        <Text size="T300" truncate>
          {room.name}
        </Text>
        {dm && (
          <Text size="T200" priority="300" truncate>
            Direct Message
          </Text>
        )}
      </Box>
    </MenuItem>
  );
}

type Props = {
  mEvent: MatrixEvent;
  onClose: () => void;
};

export function ForwardMessageDialog({ mEvent, onClose }: Props) {
  const mx = useMatrixClient();
  const modalStyle = useModalStyle(400);
  const directs = useAtomValue(mDirectAtom);
  const useAuthentication = useMediaAuthentication();
  const searchInputRef = useRef<HTMLInputElement>(null);
  const [query, setQuery] = useState('');
  const [sending, setSending] = useState(false);
  const [sentTo, setSentTo] = useState<string | null>(null);
  const [error, setError] = useState<string | null>(null);
  // Selection persists across query changes: a room selected then filtered out
  // of the rendered slice stays selected.
  const [selectedRoomIds, setSelectedRoomIds] = useState<Set<string>>(new Set());

  const toggleRoom = useCallback((roomId: string) => {
    setSelectedRoomIds((prev) => {
      const next = new Set(prev);
      if (next.has(roomId)) {
        next.delete(roomId);
      } else {
        next.add(roomId);
      }
      return next;
    });
  }, []);

  const allRooms = useMemo(
    () =>
      mx
        .getRooms()
        .filter((r) => r.getMyMembership() === 'join' && !r.isSpaceRoom())
        .sort((a, b) => (b.getLastActiveTimestamp() ?? 0) - (a.getLastActiveTimestamp() ?? 0)),
    [mx],
  );

  const filtered = useMemo(() => {
    if (!query) return allRooms;
    const q = query.toLowerCase();
    return allRooms.filter((r) => r.name.toLowerCase().includes(q));
  }, [allRooms, query]);

  const sendToSelected = useCallback(async () => {
    if (sending || selectedRoomIds.size === 0) return;
    const fwdContent = buildForwardContent(mx, mEvent);
    if (!fwdContent) {
      setError('This message could not be decrypted, so it cannot be forwarded.');
      return;
    }
    setSending(true);
    setError(null);

    const ids = [...selectedRoomIds];
    const results = await Promise.allSettled(
      // threadId-aware overload (P3-8): explicit null = send to the main timeline.
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      ids.map((id) => mx.sendEvent(id, null, mEvent.getType() as any, fwdContent)),
    );

    const failedIds: string[] = [];
    const failedNames: string[] = [];
    results.forEach((result, i) => {
      if (result.status === 'rejected') {
        failedIds.push(ids[i]);
        failedNames.push(mx.getRoom(ids[i])?.name ?? ids[i]);
      }
    });

    const total = ids.length;
    const failed = failedNames.length;
    const succeeded = total - failed;

    if (failed === 0) {
      setSentTo(`Forwarded to ${total} ${total === 1 ? 'room' : 'rooms'}`);
      setTimeout(onClose, 1400);
      return;
    }

    setSending(false);
    // Prune to only the failures so a retry doesn't re-send to rooms that
    // already succeeded (duplicate messages).
    setSelectedRoomIds(new Set(failedIds));
    if (succeeded === 0) {
      setError('Failed to forward. Try again.');
      return;
    }
    setError(`Forwarded to ${succeeded}/${total}. Failed: ${failedNames.join(', ')}.`);
  }, [mx, mEvent, onClose, sending, selectedRoomIds]);

  return (
    <Overlay open backdrop={<OverlayBackdrop />}>
      <OverlayCenter>
        <FocusTrap
          focusTrapOptions={{
            initialFocus: () => searchInputRef.current ?? false,
            onDeactivate: onClose,
            clickOutsideDeactivates: true,
            escapeDeactivates: stopPropagation,
          }}
        >
          <Modal
            size="400"
            style={{
              maxHeight: '480px',
              borderRadius: config.radii.R500,
              display: 'flex',
              flexDirection: 'column',
              ...modalStyle,
            }}
          >
            <Header
              variant="Surface"
              size="500"
              style={{ padding: `0 ${config.space.S200} 0 ${config.space.S400}` }}
            >
              <Box grow="Yes">
                <Text as="h2" size="H4" truncate>
                  Forward message
                </Text>
              </Box>
              <IconButton size="300" onClick={onClose} radii="300" aria-label="Close">
                <Icon src={Icons.Cross} />
              </IconButton>
            </Header>
            {!sentTo && (
              <Box
                shrink="No"
                direction="Column"
                style={{ padding: `${config.space.S200} ${config.space.S400}` }}
              >
                <Input
                  ref={searchInputRef}
                  variant="Background"
                  size="400"
                  radii="400"
                  outlined
                  placeholder="Search rooms…"
                  value={query}
                  onChange={(e: ChangeEvent<HTMLInputElement>) => setQuery(e.target.value)}
                />
                {error && (
                  <Text
                    size="T200"
                    style={{ color: color.Critical.Main, paddingTop: config.space.S100 }}
                  >
                    {error}
                  </Text>
                )}
              </Box>
            )}
            <Line size="300" />
            {sentTo ? (
              <Box
                grow="Yes"
                alignItems="Center"
                justifyContent="Center"
                gap="300"
                style={{ padding: config.space.S400 }}
              >
                <Text size="T300">✓ {sentTo}</Text>
              </Box>
            ) : (
              <>
                <Box grow="Yes" style={{ minHeight: 0, position: 'relative' }}>
                  <Scroll size="300" hideTrack visibility="Hover">
                    <Box direction="Column" gap="100" style={{ padding: config.space.S200 }}>
                      {filtered.slice(0, 60).map((room) => (
                        <RoomRow
                          key={room.roomId}
                          room={room}
                          dm={directs.has(room.roomId)}
                          useAuthentication={useAuthentication}
                          selected={selectedRoomIds.has(room.roomId)}
                          onToggle={() => toggleRoom(room.roomId)}
                          sending={sending}
                        />
                      ))}
                      {filtered.length === 0 && (
                        <Box
                          alignItems="Center"
                          justifyContent="Center"
                          style={{ padding: config.space.S400 }}
                        >
                          <Text size="T300" priority="300">
                            No rooms found
                          </Text>
                        </Box>
                      )}
                    </Box>
                  </Scroll>
                  {sending && (
                    <Box
                      alignItems="Center"
                      justifyContent="Center"
                      style={{
                        position: 'absolute',
                        inset: 0,
                        background: 'rgba(0,0,0,0.35)',
                        borderRadius: config.radii.R500,
                      }}
                    >
                      <Spinner variant="Secondary" size="400" />
                    </Box>
                  )}
                </Box>
                <Line size="300" />
                <Box
                  shrink="No"
                  direction="Column"
                  style={{ padding: `${config.space.S200} ${config.space.S400}` }}
                >
                  <Button
                    variant="Primary"
                    size="400"
                    radii="400"
                    disabled={selectedRoomIds.size === 0 || sending}
                    before={sending && <Spinner variant="Primary" fill="Solid" size="200" />}
                    onClick={sendToSelected}
                  >
                    <Text size="B400">
                      Send to {selectedRoomIds.size} {selectedRoomIds.size === 1 ? 'room' : 'rooms'}
                    </Text>
                  </Button>
                </Box>
              </>
            )}
          </Modal>
        </FocusTrap>
      </OverlayCenter>
    </Overlay>
  );
}
