import React, { useEffect, useRef, useState } from 'react';
import { defineMessages, useIntl } from 'react-intl';
import { Session } from 'meteor/session';
import { Meteor } from 'meteor/meteor';
import useCurrentUser from '/imports/ui/core/hooks/useCurrentUser';
import Header from '/imports/ui/components/common/control-header/component';
import { useMutation, useSubscription } from '@apollo/client';
import { Input } from '../layout/layoutTypes';
import { layoutDispatch, layoutSelectInput } from '../layout/context';
import { addAlert } from '../screenreader-alert/service';
import { PANELS, ACTIONS } from '../layout/enums';
import useMeeting from '/imports/ui/core/hooks/useMeeting';
import { POLL_CANCEL } from './mutations';
import { GetHasCurrentPresentationResponse, getHasCurrentPresentation } from './queries';
import EmptySlideArea from './components/EmptySlideArea';
import { getSplittedQuestionAndOptions, pollTypes, validateInput } from './service';
import Toggle from '/imports/ui/components/common/switch/component';
import Styled from './styles';
import ResponseChoices from './components/ResponseChoices';
import ResponseTypes from './components/ResponseTypes';
import PollQuestionArea from './components/PollQuestionArea';
import LiveResultContainer from './components/LiveResult';

const POLL_SETTINGS = Meteor.settings.public.poll;
const ALLOW_CUSTOM_INPUT = POLL_SETTINGS.allowCustomResponseInput;
const MAX_CUSTOM_FIELDS = POLL_SETTINGS.maxCustom;

const intlMessages = defineMessages({
  pollPaneTitle: {
    id: 'app.poll.pollPaneTitle',
    description: 'heading label for the poll menu',
  },
  closeLabel: {
    id: 'app.poll.closeLabel',
    description: 'label for poll pane close button',
  },
  hidePollDesc: {
    id: 'app.poll.hidePollDesc',
    description: 'aria label description for hide poll button',
  },
  quickPollInstruction: {
    id: 'app.poll.quickPollInstruction',
    description: 'instructions for using pre configured polls',
  },
  activePollInstruction: {
    id: 'app.poll.activePollInstruction',
    description: 'instructions displayed when a poll is active',
  },
  dragDropPollInstruction: {
    id: 'app.poll.dragDropPollInstruction',
    description: 'instructions for upload poll options via drag and drop',
  },
  ariaInputCount: {
    id: 'app.poll.ariaInputCount',
    description: 'aria label for custom poll input field',
  },
  customPlaceholder: {
    id: 'app.poll.customPlaceholder',
    description: 'custom poll input field placeholder text',
  },
  noPresentationSelected: {
    id: 'app.poll.noPresentationSelected',
    description: 'no presentation label',
  },
  clickHereToSelect: {
    id: 'app.poll.clickHereToSelect',
    description: 'open uploader modal button label',
  },
  questionErr: {
    id: 'app.poll.questionErr',
    description: 'question text area error label',
  },
  questionAndOptionsPlaceholder: {
    id: 'app.poll.questionAndoptions.label',
    description: 'poll input questions and options label',
  },
  customInputToggleLabel: {
    id: 'app.poll.customInput.label',
    description: 'poll custom input toogle button label',
  },
  customInputInstructionsLabel: {
    id: 'app.poll.customInputInstructions.label',
    description: 'poll custom input instructions label',
  },
  maxOptionsWarning: {
    id: 'app.poll.maxOptionsWarning.label',
    description: 'poll max options error',
  },
  optionErr: {
    id: 'app.poll.optionErr',
    description: 'poll input error label',
  },
  tf: {
    id: 'app.poll.tf',
    description: 'label for true / false poll',
  },
  a4: {
    id: 'app.poll.a4',
    description: 'label for A / B / C / D poll',
  },
  delete: {
    id: 'app.poll.optionDelete.label',
    description: '',
  },
  questionLabel: {
    id: 'app.poll.question.label',
    description: '',
  },
  optionalQuestionLabel: {
    id: 'app.poll.optionalQuestion.label',
    description: '',
  },
  userResponse: {
    id: 'app.poll.userResponse.label',
    description: '',
  },
  responseChoices: {
    id: 'app.poll.responseChoices.label',
    description: '',
  },
  typedResponseDesc: {
    id: 'app.poll.typedResponse.desc',
    description: '',
  },
  responseTypesLabel: {
    id: 'app.poll.responseTypes.label',
    description: '',
  },
  addOptionLabel: {
    id: 'app.poll.addItem.label',
    description: '',
  },
  startPollLabel: {
    id: 'app.poll.start.label',
    description: '',
  },
  secretPollLabel: {
    id: 'app.poll.secretPoll.label',
    description: '',
  },
  isSecretPollLabel: {
    id: 'app.poll.secretPoll.isSecretLabel',
    description: '',
  },
  true: {
    id: 'app.poll.answer.true',
    description: '',
  },
  false: {
    id: 'app.poll.answer.false',
    description: '',
  },
  a: {
    id: 'app.poll.answer.a',
    description: '',
  },
  b: {
    id: 'app.poll.answer.b',
    description: '',
  },
  c: {
    id: 'app.poll.answer.c',
    description: '',
  },
  d: {
    id: 'app.poll.answer.d',
    description: '',
  },
  e: {
    id: 'app.poll.answer.e',
    description: '',
  },
  yna: {
    id: 'app.poll.yna',
    description: '',
  },
  yes: {
    id: 'app.poll.y',
    description: '',
  },
  no: {
    id: 'app.poll.n',
    description: '',
  },
  abstention: {
    id: 'app.poll.abstention',
    description: '',
  },
  enableMultipleResponseLabel: {
    id: 'app.poll.enableMultipleResponseLabel',
    description: 'label for checkbox to enable multiple choice',
  },
  startPollDesc: {
    id: 'app.poll.startPollDesc',
    description: '',
  },
  showRespDesc: {
    id: 'app.poll.showRespDesc',
    description: '',
  },
  addRespDesc: {
    id: 'app.poll.addRespDesc',
    description: '',
  },
  deleteRespDesc: {
    id: 'app.poll.deleteRespDesc',
    description: '',
  },
  on: {
    id: 'app.switch.onLabel',
    description: 'label for toggle switch on state',
  },
  off: {
    id: 'app.switch.offLabel',
    description: 'label for toggle switch off state',
  },
  removePollOpt: {
    id: 'app.poll.removePollOpt',
    description: 'screen reader alert for removed poll option',
  },
  emptyPollOpt: {
    id: 'app.poll.emptyPollOpt',
    description: 'screen reader for blank poll option',
  },
  pollingQuestion: {
    id: 'app.polling.pollQuestionTitle',
    description: 'polling question header',
  },
});

interface PollCreationPanelProps {
  layoutContextDispatch: (action: {
    type: string;
    value: string | boolean;
  }) => void;
  hasPoll: boolean;
  hasCurrentPresentation: boolean;
}

const PollCreationPanel: React.FC<PollCreationPanelProps> = ({
  layoutContextDispatch,
  hasPoll,
  hasCurrentPresentation,
}) => {
  const [stopPoll] = useMutation(POLL_CANCEL);

  const intl = useIntl();
  const textareaRef = useRef<HTMLTextAreaElement | null>(null);
  const [customInput, setCustomInput] = React.useState(false);
  const [question, setQuestion] = useState<string[] | string>('');
  const [questionAndOptions, setQuestionAndOptions] = useState<string[] | string>('');
  const [optList, setOptList] = useState<Array<{val: string}>>([]);
  const [error, setError] = useState<string | null>(null);
  const [isMultipleResponse, setIsMultipleResponse] = useState(false);
  const [secretPoll, setSecretPoll] = useState(false);
  const [warning, setWarning] = useState<string | null>('');
  const [isPasting, setIsPasting] = useState(false);
  const [type, setType] = useState<string | null>('');

  const handleInputChange = (
    e: React.ChangeEvent<HTMLInputElement>,
    index: number,
  ) => {
    const list = [...optList];
    const validatedVal = validateInput(e.target.value).replace(/\s{2,}/g, ' ');
    const charsRemovedCount = e.target.value.length - validatedVal.length;
    const clearError = validatedVal.length > 0 && type !== pollTypes.Response;
    const input = e.target;
    const caretStart = e.target.selectionStart ?? 0;
    const caretEnd = e.target.selectionEnd ?? 0;
    let questionAndOptionsList: string[] = [];
    list[index] = { val: validatedVal };

    if (questionAndOptions.length > 0) {
      const QnO = questionAndOptions as string;
      questionAndOptionsList = QnO.split('\n');
      questionAndOptionsList[index + 1] = validatedVal;
    }
    setOptList(list);
    setQuestionAndOptions(questionAndOptionsList.length > 0
      ? questionAndOptionsList.join('\n') : '');
    setError(clearError ? null : error);

    input.focus();
    input.selectionStart = caretStart - charsRemovedCount;
    input.selectionEnd = caretEnd - charsRemovedCount;
  };

  const setQuestionAndOptionsFn = (input: string[] | string) => {
    const { splittedQuestion, optionsList } = getSplittedQuestionAndOptions(input);
    const optionsListLength = optionsList.length;
    let maxOptionsWarning = warning;
    const clearWarning = maxOptionsWarning && optionsListLength <= MAX_CUSTOM_FIELDS;
    const clearError = input.length > 0 && type === pollTypes.Response;

    if (optionsListLength > MAX_CUSTOM_FIELDS && optList[MAX_CUSTOM_FIELDS] === undefined) {
      setWarning(intl.formatMessage(intlMessages.maxOptionsWarning));
      if (isPasting) {
        maxOptionsWarning = intl.formatMessage(intlMessages.maxOptionsWarning);
        setIsPasting(false);
      }
    }
    setQuestionAndOptions(input);
    setOptList(optionsList);
    setQuestion(splittedQuestion);
    setError(clearError ? null : error);
    setWarning(clearWarning ? null : maxOptionsWarning);
  };

  const handleTextareaChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
    const validatedInput = validateInput(e.target.value);
    const clearError = validatedInput.length > 0 && type === pollTypes.Response;

    if (!customInput) {
      setQuestion(validatedInput);
      setError(clearError ? null : error);
    } else {
      setQuestionAndOptionsFn(validatedInput);
    }
  };

  const handleRemoveOption = (index: number) => {
    const list = [...optList];
    const removed = list[index];
    let questionAndOptionsList: string[] = [];
    let clearWarning = false;

    list.splice(index, 1);

    // If customInput then removing text from input field.
    if (customInput) {
      const QnO = questionAndOptions as string;
      questionAndOptionsList = QnO.split('\n');
      delete questionAndOptionsList[index + 1];
      questionAndOptionsList = questionAndOptionsList.filter((val: string) => val !== undefined);
      clearWarning = !!warning && list.length <= MAX_CUSTOM_FIELDS;
    }
    setOptList(list);
    setQuestionAndOptions(questionAndOptionsList.length > 0
      ? questionAndOptionsList.join('\n') : '');
    setWarning(clearWarning ? null : warning);
    addAlert(`${intl.formatMessage(intlMessages.removePollOpt,
      { 0: removed.val || intl.formatMessage(intlMessages.emptyPollOpt) })}`);
  };

  const handleAddOption = () => {
    setOptList([...optList, { val: '' }]);
  };

  const handleToggle = () => {
    const toggledValue = !secretPoll;
    Session.set('secretPoll', toggledValue);
    setSecretPoll(toggledValue);
  };

  const handlePollLetterOptions = () => {
    if (optList.length === 0) {
      setType(pollTypes.Letter);
      setOptList([
        { val: '' },
        { val: '' },
        { val: '' },
        { val: '' },
      ]);
    }
  };

  const toggleIsMultipleResponse = () => {
    setIsMultipleResponse((prev) => !prev);
    return !isMultipleResponse;
  };

  useEffect(() => {
    return () => {
      Session.set('secretPoll', false);
    };
  }, []);

  useEffect(() => {
    if (textareaRef.current) {
      textareaRef.current?.focus();
    }
  }, [textareaRef]);

  const pollOptions = () => {
    if (!hasCurrentPresentation) return <EmptySlideArea />;
    if (hasPoll) return <LiveResultContainer />;
    return (
      <>
        {
          ALLOW_CUSTOM_INPUT && (
            <Styled.CustomInputRow>
              <Styled.CustomInputHeadingCol aria-hidden="true">
                <Styled.CustomInputHeading>
                  {intl.formatMessage(intlMessages.customInputToggleLabel)}
                </Styled.CustomInputHeading>
              </Styled.CustomInputHeadingCol>
              <Styled.CustomInputToggleCol>
                <Styled.Toggle>
                  <Styled.ToggleLabel>
                    {customInput
                      ? intl.formatMessage(intlMessages.on)
                      : intl.formatMessage(intlMessages.off)}
                  </Styled.ToggleLabel>
                  <Toggle
                  // @ts-ignore - JS component wrapped by intl
                    icons={false}
                    defaultChecked={customInput}
                    onChange={() => {
                      setCustomInput(!customInput);
                      setType(pollTypes.Custom);
                    }}
                    ariaLabel={intl.formatMessage(intlMessages.customInputToggleLabel)}
                    showToggleLabel={false}
                    data-test="autoOptioningPollBtn"
                  />
                </Styled.Toggle>
              </Styled.CustomInputToggleCol>
            </Styled.CustomInputRow>
          )
        }
        {customInput && (
          <Styled.PollParagraph>
            {intl.formatMessage(intlMessages.customInputInstructionsLabel)}
          </Styled.PollParagraph>
        )}
        <PollQuestionArea
          customInput={customInput}
          question={question}
          questionAndOptions={questionAndOptions}
          handleTextareaChange={handleTextareaChange}
          error={error}
          type={type}
          textareaRef={textareaRef}
          handlePollLetterOptions={handlePollLetterOptions}
          optList={optList}
          setIsPasting={setIsPasting}
          warning={warning}
        />
        <ResponseTypes
          customInput={customInput}
          type={type}
          setOptList={setOptList}
          setType={setType}
        />
        <ResponseChoices
          type={type}
          toggleIsMultipleResponse={toggleIsMultipleResponse}
          isMultipleResponse={isMultipleResponse}
          optList={optList}
          handleAddOption={handleAddOption}
          secretPoll={secretPoll}
          question={question}
          setError={setError}
          setIsPolling={() => {
            setType(null);
            setOptList([]);
            setQuestion('');
            setQuestionAndOptions('');
          }}
          hasCurrentPresentation={hasCurrentPresentation}
          handleToggle={handleToggle}
          error={error}
          handleInputChange={handleInputChange}
          handleRemoveOption={handleRemoveOption}
          customInput={customInput}
          questionAndOptions={questionAndOptions}
        />
      </>
    );
  };

  return (
    <div>
      <Header
        data-test="pollPaneTitle"
        leftButtonProps={{
          'aria-label': intl.formatMessage(intlMessages.hidePollDesc),
          'data-test': 'hidePollDesc',
          label: intl.formatMessage(intlMessages.pollPaneTitle),
          onClick: () => {
            layoutContextDispatch({
              type: ACTIONS.SET_SIDEBAR_CONTENT_IS_OPEN,
              value: false,
            });
            layoutContextDispatch({
              type: ACTIONS.SET_SIDEBAR_CONTENT_PANEL,
              value: PANELS.NONE,
            });
          },
        }}
        rightButtonProps={{
          'aria-label': `${intl.formatMessage(intlMessages.closeLabel)} ${intl.formatMessage(intlMessages.pollPaneTitle)}`,
          'data-test': 'closePolling',
          icon: 'close',
          label: intl.formatMessage(intlMessages.closeLabel),
          onClick: () => {
            if (hasPoll) stopPoll();
            layoutContextDispatch({
              type: ACTIONS.SET_SIDEBAR_CONTENT_IS_OPEN,
              value: false,
            });
            layoutContextDispatch({
              type: ACTIONS.SET_SIDEBAR_CONTENT_PANEL,
              value: PANELS.NONE,
            });
            Session.set('forcePollOpen', false);
            Session.set('pollInitiated', false);
          },
        }}
        customRightButton={null}
      />
      {pollOptions()}
      <span className="sr-only" id="poll-config-button">{intl.formatMessage(intlMessages.showRespDesc)}</span>
      <span className="sr-only" id="add-item-button">{intl.formatMessage(intlMessages.addRespDesc)}</span>
      <span className="sr-only" id="start-poll-button">{intl.formatMessage(intlMessages.startPollDesc)}</span>
    </div>
  );
};

const PollCreationPanelContainer: React.FC = () => {
  const sidebarContent = layoutSelectInput((i: Input) => i.sidebarContent);
  const layoutContextDispatch = layoutDispatch();
  const { sidebarContentPanel } = sidebarContent;
  const {
    data: currentUser,
    loading: currentUserLoading,
  } = useCurrentUser((u) => {
    return {
      presenter: u?.presenter,
    };
  });

  const {
    data: currentMeeting,
    loading: currentMeetingLoading,
  } = useMeeting((m) => {
    return {
      componentsFlags: m?.componentsFlags,
    };
  });

  const {
    data: getHasCurrentPresentationData,
    loading: getHasCurrentPresentationLoading,
  } = useSubscription<GetHasCurrentPresentationResponse>(getHasCurrentPresentation);

  if (currentUserLoading || !currentUser) return null;
  if (currentMeetingLoading || !currentMeeting) return null;
  if (getHasCurrentPresentationLoading || !getHasCurrentPresentationData) return null;

  if (!currentUser.presenter && sidebarContentPanel === PANELS.POLL) {
    layoutContextDispatch({
      type: ACTIONS.SET_SIDEBAR_CONTENT_IS_OPEN,
      value: false,
    });
    layoutContextDispatch({
      type: ACTIONS.SET_SIDEBAR_CONTENT_PANEL,
      value: PANELS.NONE,
    });
  }

  return (
    <PollCreationPanel
      layoutContextDispatch={layoutContextDispatch}
      hasPoll={currentMeeting.componentsFlags?.hasPoll ?? false}
      hasCurrentPresentation={getHasCurrentPresentationData.pres_page_aggregate.aggregate.count > 0}
    />
  );
};

export default PollCreationPanelContainer;
