import React from 'react';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';

import {
  addPollOption,
  changePollOption,
  changePollSettings,
  clearComposeSuggestions,
  fetchComposeSuggestions,
  removePoll,
  removePollOption,
  selectComposeSuggestion,
} from '@/actions/compose';
import AutosuggestInput from '@/components/autosuggest-input';
import Button from '@/components/ui/button';
import Divider from '@/components/ui/divider';
import HStack from '@/components/ui/hstack';
import Stack from '@/components/ui/stack';
import Text from '@/components/ui/text';
import Toggle from '@/components/ui/toggle';
import { useAppDispatch } from '@/hooks/use-app-dispatch';
import { useCompose } from '@/hooks/use-compose';
import { useInstance } from '@/hooks/use-instance';

import DurationSelector from './duration-selector';

import type { AutoSuggestion } from '@/components/autosuggest-input';

const messages = defineMessages({
  optionPlaceholder: {
    id: 'compose_form.poll.option_placeholder',
    defaultMessage: 'Answer #{number}',
  },
  pollDuration: { id: 'compose_form.poll.duration', defaultMessage: 'Poll duration' },
  removePoll: { id: 'compose_form.poll.remove', defaultMessage: 'Remove poll' },
  switchToMultiple: {
    id: 'compose_form.poll.switch_to_multiple',
    defaultMessage: 'Change poll to allow multiple answers',
  },
  switchToSingle: {
    id: 'compose_form.poll.switch_to_single',
    defaultMessage: 'Change poll to allow for a single answer',
  },
  multiSelect: { id: 'compose_form.poll.multiselect', defaultMessage: 'Multi-select' },
  multiSelectDetail: {
    id: 'compose_form.poll.multiselect_detail',
    defaultMessage: 'Allow users to select multiple answers',
  },
});

interface IOption {
  composeId: string;
  index: number;
  maxChars: number;
  numOptions: number;
  onChange(index: number, value: string): void;
  onRemove(index: number): void;
  onRemovePoll(): void;
  title: string;
}

const Option: React.FC<IOption> = ({
  composeId,
  index,
  maxChars,
  numOptions,
  onChange,
  onRemove,
  onRemovePoll,
  title,
}) => {
  const dispatch = useAppDispatch();
  const intl = useIntl();

  const { suggestions, modifiedLanguage: language } = useCompose(composeId);

  const handleOptionTitleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    onChange(index, event.target.value);
  };

  const handleOptionRemove = () => {
    if (numOptions > 2) {
      onRemove(index);
    } else {
      onRemovePoll();
    }
  };

  const onSuggestionsClearRequested = () => dispatch(clearComposeSuggestions(composeId));

  const onSuggestionsFetchRequested = (token: string) => {
    dispatch(fetchComposeSuggestions(composeId, token));
  };

  const onSuggestionSelected = (
    tokenStart: number,
    token: string | null,
    value: AutoSuggestion,
  ) => {
    if (token && typeof token === 'string') {
      dispatch(
        selectComposeSuggestion(composeId, tokenStart, token, value, ['poll', 'options', index]),
      );
    }
  };

  return (
    <div className='⁂-compose-form__poll__option'>
      <HStack alignItems='center' space={2} grow>
        <div className='w-6'>
          <Text weight='bold'>{index + 1}.</Text>
        </div>

        <AutosuggestInput
          className='rounded-md !bg-transparent dark:!bg-transparent'
          placeholder={intl.formatMessage(messages.optionPlaceholder, { number: index + 1 })}
          maxLength={maxChars}
          value={title}
          onChange={handleOptionTitleChange}
          suggestions={suggestions}
          onSuggestionsFetchRequested={onSuggestionsFetchRequested}
          onSuggestionsClearRequested={onSuggestionsClearRequested}
          onSuggestionSelected={onSuggestionSelected}
          searchTokens={[':']}
          autoFocus={index === 0 || index >= 2}
          lang={language ?? undefined}
        />
      </HStack>

      {index > 1 && (
        <div>
          <Button theme='danger' size='sm' onClick={handleOptionRemove}>
            <FormattedMessage
              id='compose_form.poll.remove_option'
              defaultMessage='Remove this answer'
            />
          </Button>
        </div>
      )}
    </div>
  );
};

interface IPollForm {
  composeId: string;
}

const PollForm: React.FC<IPollForm> = ({ composeId }) => {
  const dispatch = useAppDispatch();
  const intl = useIntl();
  const { configuration } = useInstance();

  const { poll, language, modifiedLanguage } = useCompose(composeId);

  const options =
    !modifiedLanguage || modifiedLanguage === language
      ? poll?.options
      : poll?.options_map.map((option, key) => option[modifiedLanguage] || poll.options[key]);
  const expiresIn = poll?.expires_in;
  const isMultiple = poll?.multiple;

  const { max_options: maxOptions, max_characters_per_option: maxOptionChars } =
    configuration.polls;

  const onRemoveOption = (index: number) => dispatch(removePollOption(composeId, index));
  const onChangeOption = (index: number, title: string) =>
    dispatch(changePollOption(composeId, index, title));
  const handleAddOption = () => dispatch(addPollOption(composeId, ''));
  const onChangeSettings = (expiresIn: number, isMultiple?: boolean) =>
    dispatch(changePollSettings(composeId, expiresIn, isMultiple));
  const handleSelectDuration = (value: number) => onChangeSettings(value, isMultiple);
  const handleToggleMultiple = () => onChangeSettings(Number(expiresIn), !isMultiple);
  const onRemovePoll = () => dispatch(removePoll(composeId));

  if (!options) {
    return null;
  }

  return (
    <div className='⁂-compose-form__poll'>
      <div className='⁂-compose-form__poll__options'>
        {options.map((title: string, i: number) => (
          <Option
            composeId={composeId}
            title={title}
            key={i}
            index={i}
            onChange={onChangeOption}
            onRemove={onRemoveOption}
            maxChars={maxOptionChars}
            numOptions={options.length}
            onRemovePoll={onRemovePoll}
          />
        ))}

        <HStack space={2}>
          <div className='w-6' />

          {options.length < maxOptions && (
            <Button theme='secondary' onClick={handleAddOption} size='sm' block>
              <FormattedMessage id='compose_form.poll.add_option' defaultMessage='Add an answer' />
            </Button>
          )}
        </HStack>
      </div>

      <Divider />

      <label className='text-start'>
        <HStack alignItems='center' justifyContent='between'>
          <Stack>
            <Text weight='medium'>{intl.formatMessage(messages.multiSelect)}</Text>

            <Text theme='muted' size='sm'>
              {intl.formatMessage(messages.multiSelectDetail)}
            </Text>
          </Stack>

          <Toggle checked={isMultiple} onChange={handleToggleMultiple} />
        </HStack>
      </label>

      <Divider />

      {/* Duration */}
      <Stack space={2}>
        <Text weight='medium'>{intl.formatMessage(messages.pollDuration)}</Text>

        <DurationSelector
          onDurationChange={handleSelectDuration}
          value={expiresIn ?? 2 * 24 * 60 * 60}
        />
      </Stack>

      {/* Remove Poll */}
      <div className='text-center'>
        <button type='button' className='text-danger-500' onClick={onRemovePoll}>
          {intl.formatMessage(messages.removePoll)}
        </button>
      </div>
    </div>
  );
};

export { PollForm as default };
