import React, { ChangeEventHandler, FormEventHandler, useCallback, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { IPushRule, IPushRules, PushRuleKind } from 'matrix-js-sdk';
import { Box, Text, Button, Input, config, IconButton, Icons, Icon, Spinner } from 'folds';
import { useAccountData } from '../../../hooks/useAccountData';
import { AccountDataEvent } from '../../../../types/matrix/accountData';
import { SettingTile } from '../../../components/setting-tile';
import { SettingsSection } from '../SettingsSection';
import { Mono } from '../styles.css';
import { useMatrixClient } from '../../../hooks/useMatrixClient';
import {
  getNotificationModeActions,
  NotificationMode,
  NotificationModeOptions,
} from '../../../hooks/useNotificationMode';
import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback';

const NOTIFY_MODE_OPS: NotificationModeOptions = {
  highlight: true,
};

function KeywordInput() {
  const { t } = useTranslation();
  const mx = useMatrixClient();
  const [keyword, setKeyword] = useState<string>('');

  const [keywordState, addKeyword] = useAsyncCallback(
    useCallback(
      async (k: string) => {
        mx.addPushRule('global', PushRuleKind.ContentSpecific, k, {
          actions: getNotificationModeActions(NotificationMode.Notify, NOTIFY_MODE_OPS),
          pattern: k,
        });
        setKeyword('');
      },
      [mx]
    )
  );
  const addingKeyword = keywordState.status === AsyncStatus.Loading;

  const handleChange: ChangeEventHandler<HTMLInputElement> = (evt) => {
    const k = evt.currentTarget.value;
    setKeyword(k);
  };

  const handleReset = () => {
    setKeyword('');
  };

  const handleSubmit: FormEventHandler<HTMLFormElement> = (evt) => {
    evt.preventDefault();
    if (addingKeyword) return;

    const target = evt.target as HTMLFormElement | undefined;
    const keywordInput = target?.keywordInput as HTMLInputElement | undefined;
    const k = keywordInput?.value.trim();
    if (!k) return;

    addKeyword(k);
  };

  return (
    <Box as="form" onSubmit={handleSubmit} gap="200" aria-disabled={addingKeyword}>
      <Box grow="Yes" direction="Column">
        <Input
          required
          name="keywordInput"
          value={keyword}
          onChange={handleChange}
          variant="Secondary"
          radii="300"
          style={{ paddingRight: config.space.S200 }}
          readOnly={addingKeyword}
          after={
            keyword &&
            !addingKeyword && (
              <IconButton
                type="reset"
                onClick={handleReset}
                size="300"
                radii="300"
                variant="Secondary"
              >
                <Icon src={Icons.Cross} size="100" />
              </IconButton>
            )
          }
        />
      </Box>
      <Button
        size="400"
        variant="Secondary"
        fill="Soft"
        outlined
        radii="300"
        type="submit"
        disabled={addingKeyword}
      >
        {addingKeyword && <Spinner variant="Secondary" size="300" />}
        <Text size="B400">{t('Settings.save')}</Text>
      </Button>
    </Box>
  );
}

type PushRulesProps = {
  pushRule: IPushRule;
};

function KeywordCross({ pushRule }: PushRulesProps) {
  const mx = useMatrixClient();
  const [removeState, remove] = useAsyncCallback(
    useCallback(
      () => mx.deletePushRule('global', PushRuleKind.ContentSpecific, pushRule.rule_id),
      [mx, pushRule]
    )
  );

  const removing = removeState.status === AsyncStatus.Loading;
  return (
    <IconButton onClick={remove} size="300" radii="Pill" variant="Secondary" disabled={removing}>
      {removing ? <Spinner size="100" /> : <Icon src={Icons.Cross} size="100" />}
    </IconButton>
  );
}

export function KeywordMessagesNotifications() {
  const { t } = useTranslation();
  const pushRulesEvt = useAccountData(AccountDataEvent.PushRules);
  const pushRules = useMemo(
    () => pushRulesEvt?.getContent<IPushRules>() ?? { global: {} },
    [pushRulesEvt]
  );

  const keywordPushRules = useMemo(() => {
    const content = pushRules.global.content ?? [];
    return content.filter(
      (pushRule) => pushRule.default === false && typeof pushRule.pattern === 'string'
    );
  }, [pushRules]);

  return (
    <SettingsSection label={t('Settings.keyword_messages')}>
      <SettingTile
        title={t('Settings.select_keyword')}
        description={t('Settings.select_keyword_desc')}
      >
        <KeywordInput />
      </SettingTile>
      {keywordPushRules.map((pushRule) => (
        <SettingTile
          key={pushRule.rule_id}
          title={
            <Text as="span" size="T300" className={Mono}>
              {`"${pushRule.pattern}"`}
            </Text>
          }
          before={<KeywordCross pushRule={pushRule} />}
        />
      ))}
    </SettingsSection>
  );
}
