import React, { FormEventHandler, useState } from 'react';
import {
  Box,
  Button,
  Header,
  Icon,
  IconButton,
  Icons,
  Input,
  Scroll,
  Spinner,
  Text,
  Tooltip,
  TooltipProvider,
  color,
  config,
} from 'folds';
import { Room } from 'matrix-js-sdk';
import classNames from 'classnames';
import * as css from './WidgetsPanel.css';
import { ContainerColor } from '../../../styles/ContainerColor.css';
import { RoomWidgetView } from './RoomWidgetView';
import { useRoomWidgets } from './useRoomWidgets';
import { useMatrixClient } from '../../../hooks/useMatrixClient';
import { usePowerLevelsContext } from '../../../hooks/usePowerLevels';
import { useRoomCreators } from '../../../hooks/useRoomCreators';
import { useRoomPermissions } from '../../../hooks/useRoomPermissions';
import { StateEvent } from '../../../../types/matrix/room';
import { sendStateEvent } from '../../../utils/room';
import { generateWidgetId, validateWidgetUrl, WidgetUrlError } from './widgetUtils';

const urlErrorMessage = (err: WidgetUrlError): string => {
  switch (err) {
    case 'empty':
      return 'Enter a widget URL.';
    case 'not-https':
      return 'Widget URLs must use https.';
    case 'same-origin':
      return 'That URL is not allowed (it is on this app’s own origin).';
    default:
      return 'That is not a valid URL.';
  }
};

type WidgetsPanelProps = {
  room: Room;
  requestClose: () => void;
};
export function WidgetsPanel({ room, requestClose }: WidgetsPanelProps) {
  const mx = useMatrixClient();
  const widgets = useRoomWidgets(room);
  const powerLevels = usePowerLevelsContext();
  const creators = useRoomCreators(room);
  const permissions = useRoomPermissions(creators, powerLevels);
  const canModify = permissions.stateEvent(StateEvent.Widget, mx.getSafeUserId());

  const [viewingId, setViewingId] = useState<string | null>(null);
  const [adding, setAdding] = useState(false);
  const [saving, setSaving] = useState(false);
  const [error, setError] = useState<string>();

  const viewing = widgets.find((w) => w.id === viewingId) ?? null;

  const handleAdd: FormEventHandler<HTMLFormElement> = async (evt) => {
    evt.preventDefault();
    const target = evt.target as HTMLFormElement;
    const nameInput = target.elements.namedItem('widgetName') as HTMLInputElement | null;
    const urlInput = target.elements.namedItem('widgetUrl') as HTMLInputElement | null;
    if (!urlInput) return;
    const urlErr = validateWidgetUrl(urlInput.value, window.location.origin);
    if (urlErr) {
      setError(urlErrorMessage(urlErr));
      return;
    }
    setError(undefined);
    setSaving(true);
    const id = generateWidgetId();
    const content = {
      id,
      type: 'm.custom',
      url: urlInput.value.trim(),
      name: nameInput?.value.trim() || 'Widget',
      creatorUserId: mx.getSafeUserId(),
      data: {},
    };
    try {
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      await sendStateEvent(mx, room.roomId, StateEvent.Widget, content, id);
      setAdding(false);
    } catch (e) {
      setError((e as Error).message);
    } finally {
      setSaving(false);
    }
  };

  const handleRemove = (id: string) => {
    if (viewingId === id) setViewingId(null);
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    sendStateEvent(mx, room.roomId, StateEvent.Widget, {}, id).catch(() => undefined);
  };

  return (
    <Box
      shrink="No"
      className={classNames(css.WidgetsPanel, ContainerColor({ variant: 'Surface' }))}
      direction="Column"
    >
      <Header className={css.WidgetsPanelHeader} variant="Background" size="600">
        <Box grow="Yes" alignItems="Center" gap="200">
          <Box grow="Yes" direction="Column">
            <Text size="H5" truncate>
              Widgets
            </Text>
            <Text size="T200" truncate style={{ opacity: 0.65 }}>
              {room.name}
            </Text>
          </Box>
          <Box shrink="No">
            <TooltipProvider
              position="Bottom"
              align="End"
              offset={4}
              tooltip={
                <Tooltip>
                  <Text>Close</Text>
                </Tooltip>
              }
            >
              {(triggerRef) => (
                <IconButton
                  ref={triggerRef}
                  variant="Background"
                  aria-label="Close widgets"
                  onClick={requestClose}
                >
                  <Icon src={Icons.Cross} />
                </IconButton>
              )}
            </TooltipProvider>
          </Box>
        </Box>
      </Header>

      <Box grow="Yes" className={css.WidgetsPanelContent}>
        {viewing ? (
          <Box grow="Yes" direction="Column">
            <Box shrink="No" style={{ padding: config.space.S200 }}>
              <Button
                variant="Secondary"
                fill="Soft"
                size="300"
                radii="300"
                onClick={() => setViewingId(null)}
                before={<Icon size="100" src={Icons.ArrowLeft} />}
              >
                <Text size="B300" truncate>
                  {viewing.name || 'Widget'}
                </Text>
              </Button>
            </Box>
            <RoomWidgetView room={room} widget={viewing} />
          </Box>
        ) : (
          <Scroll hideTrack visibility="Hover">
            <Box direction="Column" gap="200" style={{ padding: config.space.S300 }}>
              {widgets.length === 0 && (
                <Text size="T200" style={{ opacity: 0.65 }}>
                  No widgets in this room yet.
                </Text>
              )}
              {widgets.map((widget) => (
                <Box key={widget.id} alignItems="Center" gap="200">
                  <Box
                    as="button"
                    type="button"
                    grow="Yes"
                    alignItems="Center"
                    gap="200"
                    onClick={() => setViewingId(widget.id)}
                    style={{ cursor: 'pointer', minWidth: 0 }}
                  >
                    <Icon size="100" src={Icons.Category} />
                    <Text size="T300" truncate>
                      {widget.name || widget.templateUrl}
                    </Text>
                  </Box>
                  {canModify && (
                    <IconButton
                      size="300"
                      radii="300"
                      variant="Background"
                      aria-label={`Remove ${widget.name || 'widget'}`}
                      onClick={() => handleRemove(widget.id)}
                    >
                      <Icon size="100" src={Icons.Delete} />
                    </IconButton>
                  )}
                </Box>
              ))}

              {canModify &&
                (adding ? (
                  <Box
                    as="form"
                    direction="Column"
                    gap="200"
                    onSubmit={handleAdd}
                    style={{ marginTop: config.space.S200 }}
                  >
                    <Input
                      name="widgetName"
                      placeholder="Name (optional)"
                      variant="Secondary"
                      radii="300"
                    />
                    <Input
                      name="widgetUrl"
                      placeholder="https://…"
                      variant="Secondary"
                      radii="300"
                      required
                    />
                    <Box gap="200">
                      <Button
                        type="submit"
                        size="300"
                        variant="Primary"
                        fill="Solid"
                        radii="300"
                        disabled={saving}
                        before={
                          saving ? <Spinner size="100" variant="Primary" fill="Solid" /> : undefined
                        }
                      >
                        <Text size="B300">Add</Text>
                      </Button>
                      <Button
                        type="button"
                        size="300"
                        variant="Secondary"
                        fill="Soft"
                        radii="300"
                        onClick={() => {
                          setAdding(false);
                          setError(undefined);
                        }}
                      >
                        <Text size="B300">Cancel</Text>
                      </Button>
                    </Box>
                  </Box>
                ) : (
                  <Button
                    variant="Secondary"
                    fill="Soft"
                    size="300"
                    radii="300"
                    onClick={() => setAdding(true)}
                    before={<Icon size="100" src={Icons.Plus} />}
                    style={{ marginTop: config.space.S200 }}
                  >
                    <Text size="B300">Add Widget</Text>
                  </Button>
                ))}
              {error && (
                <Text size="T200" style={{ color: color.Critical.Main }}>
                  {error}
                </Text>
              )}
            </Box>
          </Scroll>
        )}
      </Box>
    </Box>
  );
}
