import React, { useState, useCallback } from 'react';
import {
  Box,
  Button,
  Text,
  Icon,
  Icons,
  config,
  IconButton,
  Chip,
  Line,
} from 'folds';
import { useAtomValue } from 'jotai';
import { useMatrixClient } from '../../../hooks/useMatrixClient';
import { useRoom } from '../../../hooks/useRoom';
import { useRoomSubRooms, PaarrotSubRoomsContent } from '../../../hooks/useRoomSubRooms';
import { useAllJoinedRoomsSet, useGetRoom } from '../../../hooks/useGetRoom';
import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback';
import { SettingTile } from '../../../components/setting-tile';
import { StateEvent } from '../../../../types/matrix/room';
import { usePowerLevels } from '../../../hooks/usePowerLevels';
import { useRoomCreators } from '../../../hooks/useRoomCreators';
import { useRoomPermissions } from '../../../hooks/useRoomPermissions';
import { roomToParentsAtom } from '../../../state/room/roomToParents';
import { isSpace } from '../../../utils/room';

function SubRoomItem({ roomId, onRemove, canEdit }: { roomId: string; onRemove: (roomId: string) => void; canEdit: boolean }) {
  const allJoinedRooms = useAllJoinedRoomsSet();
  const getRoom = useGetRoom(allJoinedRooms);
  const room = getRoom(roomId);

  if (!room) {
    return (
      <Chip variant="Secondary" radii="400">
        <Text size="T300">Unknown Room ({roomId})</Text>
        {canEdit && (
          <IconButton
            variant="SurfaceVariant"
            size="300"
            radii="Pill"
            onClick={() => onRemove(roomId)}
          >
            <Icon size="50" src={Icons.Cross} />
          </IconButton>
        )}
      </Chip>
    );
  }

  return (
    <Chip variant="Secondary" radii="400">
      <Text size="T300">{room.name}</Text>
      {canEdit && (
        <IconButton
          variant="SurfaceVariant"
          size="300"
          radii="Pill"
          onClick={() => onRemove(roomId)}
        >
          <Icon size="50" src={Icons.Cross} />
        </IconButton>
      )}
    </Chip>
  );
}

export function SubRooms() {
  const mx = useMatrixClient();
  const room = useRoom();
  const subRooms = useRoomSubRooms(room);
  const [addRoomId, setAddRoomId] = useState('');
  const roomToParents = useAtomValue(roomToParentsAtom);

  const powerLevels = usePowerLevels(room);
  const creators = useRoomCreators(room);
  const permissions = useRoomPermissions(creators, powerLevels);
  const canEdit = permissions.stateEvent(StateEvent.PaarrotSubRooms, mx.getSafeUserId());

  const [updateState, updateSubRooms] = useAsyncCallback(
    useCallback(
      async (newSubRooms: string[]) => {
        const content: PaarrotSubRoomsContent = {
          children: newSubRooms,
        };
        // Custom state event type - need to cast
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        await mx.sendStateEvent(room.roomId, StateEvent.PaarrotSubRooms as any, content, '');
      },
      [mx, room]
    )
  );

  const handleRemoveSubRoom = useCallback(
    (roomId: string) => {
      const newSubRooms = subRooms.filter(id => id !== roomId);
      updateSubRooms(newSubRooms);
    },
    [subRooms, updateSubRooms]
  );

  const handleAddRoom = useCallback(async () => {
    const trimmedId = addRoomId.trim();
    if (!trimmedId) return;
    
    // Try to resolve room - if it's already joined, use the actual room ID
    const targetRoom = mx.getRoom(trimmedId);
    const roomIdToAdd = targetRoom ? targetRoom.roomId : trimmedId;
    
    // Allow adding any room ID (even if not joined)
    if (!subRooms.includes(roomIdToAdd)) {
      const newSubRooms = [...subRooms, roomIdToAdd];
      await updateSubRooms(newSubRooms);

      // Also add sub-room to this room's parent space(s) for joining/permissions
      // The UI will hide it from the top-level display and only show it nested
      const parentSpaces = roomToParents.get(room.roomId);
      if (parentSpaces) {
        const spaceIds = Array.from(parentSpaces);
        await Promise.all(
          spaceIds.map(async (parentSpaceId) => {
            const parentSpaceRoom = mx.getRoom(parentSpaceId);
            // Only add to actual spaces (not other sub-room parents)
            if (parentSpaceRoom && isSpace(parentSpaceRoom)) {
              try {
                const spaceServerName = parentSpaceId.split(':')[1] || '';
                const spaceViaServers = spaceServerName ? [spaceServerName] : [];
                // Add as m.space.child to the space
                await mx.sendStateEvent(
                  parentSpaceId,
                  // eslint-disable-next-line @typescript-eslint/no-explicit-any
                  StateEvent.SpaceChild as any,
                  { via: spaceViaServers },
                  roomIdToAdd
                );
              } catch (spaceError) {
                // eslint-disable-next-line no-console
                console.warn(`Failed to add sub-room to space ${parentSpaceId}:`, spaceError);
              }
            }
          })
        );
      }

      setAddRoomId('');
    }
  }, [mx, addRoomId, subRooms, updateSubRooms, room.roomId, roomToParents]);

  return (
    <Box direction="Column" gap="400">
      <SettingTile>
        <Box direction="Column" gap="200">
          <Text size="H5" priority="400">
            Sub-Rooms
          </Text>
          <Text size="T300" priority="300">
            Sub-rooms are nested rooms that appear indented under this room in the room list.
            They work like sub-spaces but for regular rooms.
          </Text>
        </Box>
      </SettingTile>

      <Line variant="Surface" size="300" />

      <SettingTile>
        <Box direction="Column" gap="300">
          <Box justifyContent="SpaceBetween" alignItems="Center">
            <Text size="T400" priority="400">
              Current Sub-Rooms
            </Text>
          </Box>

          <Box gap="200" alignItems="Center">
            <input
              type="text"
              placeholder="Enter room ID (!abc:server.com) or alias (#room:server.com)"
              value={addRoomId}
              onChange={(e) => setAddRoomId(e.target.value)}
              onKeyDown={(e) => {
                if (e.key === 'Enter') {
                  handleAddRoom();
                }
              }}
              style={{
                flexGrow: 1,
                padding: `${config.space.S200} ${config.space.S300}`,
                borderRadius: config.radii.R400,
                border: '1px solid var(--border-surface)',
                backgroundColor: 'var(--background-surface)',
                color: 'var(--text-primary)',
                fontSize: config.fontSize.T300,
              }}
            />
            <Button
              variant="Primary"
              size="300"
              radii="Pill"
              onClick={handleAddRoom}
              disabled={!canEdit || updateState.status === AsyncStatus.Loading || !addRoomId.trim()}
              before={<Icon size="100" src={Icons.Plus} />}
            >
              <Text size="B300">Add</Text>
            </Button>
          </Box>

          {!canEdit && (
            <Text size="T300" priority="300" style={{ fontStyle: 'italic' }}>
              You need power level 50 or higher to manage sub-rooms.
            </Text>
          )}

          {subRooms.length === 0 ? (
            <Box
              direction="Column"
              alignItems="Center"
              justifyContent="Center"
              gap="200"
              style={{ padding: `${config.space.S400} 0` }}
            >
              <Icon size="400" src={Icons.Hash} style={{ opacity: config.opacity.P300 }} />
              <Text size="T300" priority="300" align="Center">
                No sub-rooms added yet.
                <br />
                Add a room to nest it under this room.
              </Text>
            </Box>
          ) : (
            <Box wrap="Wrap" gap="200">
              {subRooms.map((roomId) => (
                <SubRoomItem key={roomId} roomId={roomId} onRemove={handleRemoveSubRoom} canEdit={canEdit} />
              ))}
            </Box>
          )}

          {updateState.status === AsyncStatus.Error && (
            <Text size="T300" priority="400" style={{ color: 'var(--color-critical)' }}>
              Failed to update sub-rooms: {String((updateState.error as Error)?.message || updateState.error)}
            </Text>
          )}
        </Box>
      </SettingTile>
    </Box>
  );
}
