import React, { FormEventHandler, useCallback, useState } from 'react';
import { Box, Button, Chip, color, config, Input, Spinner, Text, Tooltip, TooltipProvider } from 'folds';
import { Icon, Icons } from '../../../components/icons';
import { SequenceCard } from '../../../components/sequence-card';
import { SequenceCardStyle } from '../../room-settings/styles.css';
import { SettingTile } from '../../../components/setting-tile';
import { useRoom } from '../../../hooks/useRoom';
import {
  useRoomEmbedFilters,
  useRoomWideEmbedFilters,
  useSetRoomWideEmbedFilters,
  EmbedFiltersContent,
} from '../../../hooks/useRoomEmbedFilters';
import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback';
import { useMatrixClient } from '../../../hooks/useMatrixClient';
import { usePowerLevels } from '../../../hooks/usePowerLevels';
import { useRoomCreators } from '../../../hooks/useRoomCreators';
import { useRoomPermissions } from '../../../hooks/useRoomPermissions';
import { StateEvent } from '../../../../types/matrix/room';

/**
 * Validates that a string is a valid regex pattern.
 * @param pattern - The pattern to validate
 * @returns True if the pattern is valid
 */
const isValidPattern = (pattern: string): boolean => {
  try {
    // eslint-disable-next-line no-new
    new RegExp(pattern);
    return true;
  } catch {
    return false;
  }
};

/**
 * Props for the pattern list editor component.
 */
interface PatternListEditorProps {
  patterns: string[];
  onAdd: (pattern: string) => Promise<void>;
  onRemove: (pattern: string) => Promise<void>;
  disabled?: boolean;
  saving: boolean;
  error?: string;
}

/**
 * Reusable component for adding/removing patterns.
 */
function PatternListEditor({
  patterns,
  onAdd,
  onRemove,
  disabled,
  saving,
  error,
}: PatternListEditorProps) {
  const [newPattern, setNewPattern] = useState('');
  const [patternError, setPatternError] = useState<string>();

  const handleAddPattern: FormEventHandler<HTMLFormElement> = async (evt) => {
    evt.preventDefault();
    const pattern = newPattern.trim();

    if (!pattern) {
      setPatternError('Pattern cannot be empty');
      return;
    }

    if (!isValidPattern(pattern)) {
      setPatternError('Invalid regex pattern');
      return;
    }

    if (patterns.includes(pattern)) {
      setPatternError('Pattern already exists');
      return;
    }

    setPatternError(undefined);
    await onAdd(pattern);
    setNewPattern('');
  };

  return (
    <Box direction="Column" gap="300">
      <Box as="form" onSubmit={handleAddPattern} gap="200" alignItems="Start">
        <Box grow="Yes" direction="Column" gap="100">
          <Input
            value={newPattern}
            onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
              setNewPattern(e.target.value);
              setPatternError(undefined);
            }}
            placeholder="e.g. ^https?://example\.com"
            size="300"
            variant="Secondary"
            radii="300"
            disabled={disabled || saving}
            style={{ width: '100%' }}
          />
          {patternError && (
            <Text size="T200" style={{ color: color.Critical.Main }}>
              {patternError}
            </Text>
          )}
        </Box>
        <Button
          type="submit"
          size="300"
          variant="Primary"
          fill="Solid"
          radii="300"
          disabled={disabled || saving || !newPattern.trim()}
          before={saving && <Spinner size="100" variant="Primary" fill="Solid" />}
        >
          <Text size="B300">Add</Text>
        </Button>
      </Box>

      {patterns.length > 0 && (
        <Box direction="Column" gap="200">
          <Text size="T200" priority="300">
            Active patterns ({patterns.length}):
          </Text>
          <Box gap="200" wrap="Wrap">
            {patterns.map((pattern) => (
              <TooltipProvider
                key={pattern}
                tooltip={
                  <Tooltip>
                    <Text size="T300">{pattern}</Text>
                  </Tooltip>
                }
              >
                {(triggerRef) => (
                  <Chip
                    ref={triggerRef}
                    variant="Secondary"
                    radii="Pill"
                    onClick={() => onRemove(pattern)}
                    after={!disabled && <Icon size="50" src={Icons.Cross} />}
                    disabled={disabled || saving}
                  >
                    <Text
                      size="T200"
                      truncate
                      style={{ maxWidth: config.space.S500, fontFamily: 'monospace' }}
                    >
                      {pattern}
                    </Text>
                  </Chip>
                )}
              </TooltipProvider>
            ))}
          </Box>
        </Box>
      )}

      {error && (
        <Text size="T200" style={{ color: color.Critical.Main }}>
          Failed to save: {error}
        </Text>
      )}
    </Box>
  );
}

/**
 * Component for managing personal URL embed filter patterns for a room.
 * These patterns are stored per-user per-room and filter out URL previews
 * that match the patterns.
 */
export function PersonalEmbedFilters() {
  const room = useRoom();
  const [filters, setFilters] = useRoomEmbedFilters(room);

  const [saveState, saveFilters] = useAsyncCallback(
    useCallback(
      async (newFilters: EmbedFiltersContent) => {
        await setFilters(newFilters);
      },
      [setFilters]
    )
  );

  const saving = saveState.status === AsyncStatus.Loading;

  const handleAdd = async (pattern: string) => {
    const newFilters: EmbedFiltersContent = {
      disabledPatterns: [...filters.disabledPatterns, pattern],
    };
    await saveFilters(newFilters);
  };

  const handleRemove = async (pattern: string) => {
    const newFilters: EmbedFiltersContent = {
      disabledPatterns: filters.disabledPatterns.filter((p) => p !== pattern),
    };
    await saveFilters(newFilters);
  };

  return (
    <SequenceCard
      className={SequenceCardStyle}
      variant="SurfaceVariant"
      direction="Column"
      gap="400"
    >
      <SettingTile
        title="Personal Embed Filters"
        description="Add regex patterns for URLs that should not show embeds for you only. Patterns are case-insensitive."
      />
      <PatternListEditor
        patterns={filters.disabledPatterns}
        onAdd={handleAdd}
        onRemove={handleRemove}
        saving={saving}
        error={saveState.status === AsyncStatus.Error ? String(saveState.error) : undefined}
      />
    </SequenceCard>
  );
}

/**
 * Component for managing room-wide URL embed filter patterns.
 * These patterns are set by room admins and apply to all users.
 */
export function RoomWideEmbedFilters() {
  const room = useRoom();
  const mx = useMatrixClient();
  const powerLevels = usePowerLevels(room);
  const creators = useRoomCreators(room);
  const permissions = useRoomPermissions(creators, powerLevels);

  const canEdit = permissions.stateEvent(StateEvent.RoomEmbedFilters, mx.getSafeUserId());
  const filters = useRoomWideEmbedFilters(room);
  const setRoomWideFilters = useSetRoomWideEmbedFilters(room);

  const [saveState, saveFilters] = useAsyncCallback(
    useCallback(
      async (newFilters: EmbedFiltersContent) => {
        await setRoomWideFilters(newFilters);
      },
      [setRoomWideFilters]
    )
  );

  const saving = saveState.status === AsyncStatus.Loading;

  const handleAdd = async (pattern: string) => {
    const newFilters: EmbedFiltersContent = {
      disabledPatterns: [...filters.disabledPatterns, pattern],
    };
    await saveFilters(newFilters);
  };

  const handleRemove = async (pattern: string) => {
    const newFilters: EmbedFiltersContent = {
      disabledPatterns: filters.disabledPatterns.filter((p) => p !== pattern),
    };
    await saveFilters(newFilters);
  };

  return (
    <SequenceCard
      className={SequenceCardStyle}
      variant="SurfaceVariant"
      direction="Column"
      gap="400"
    >
      <SettingTile
        title="Room-Wide Embed Filters"
        description={
          canEdit
            ? 'Add regex patterns that apply to all users in this room. Patterns are case-insensitive.'
            : 'Embed filter patterns set by room admins. You need moderator permissions to edit.'
        }
      />
      <PatternListEditor
        patterns={filters.disabledPatterns}
        onAdd={handleAdd}
        onRemove={handleRemove}
        disabled={!canEdit}
        saving={saving}
        error={saveState.status === AsyncStatus.Error ? String(saveState.error) : undefined}
      />
    </SequenceCard>
  );
}

/**
 * Combined component showing both personal and room-wide embed filters.
 */
export function EmbedFilters() {
  return (
    <Box direction="Column" gap="400">
      <RoomWideEmbedFilters />
      <PersonalEmbedFilters />
    </Box>
  );
}
