import { FC, useEffect, useState } from 'react';
import { FormProvider, useForm } from 'react-hook-form';
import { useMutation } from 'react-query';

import { AxiosResponse } from 'axios';
import { IconChartBarPopular, IconX } from '@material-hu/icons/tabler';
import Grid from '@material-hu/mui/Grid';
import IconButton from '@material-hu/mui/IconButton/IconButton';
import Stack from '@material-hu/mui/Stack/Stack';
import useTheme from '@material-hu/mui/styles/useTheme';
import Typography from '@material-hu/mui/Typography/Typography';

import FormSelectionCard from '@material-hu/components/composed-components/SelectionCard/form';
import Button from '@material-hu/components/design-system/Buttons/Button';
import CardContainer from '@material-hu/components/design-system/CardContainer';
import ProgressBar from '@material-hu/components/design-system/ProgressIndicators/ProgressBar';
import RadioButton from '@material-hu/components/design-system/RadioButton/RadioButton';

import { queryClient } from 'src/config/react-query';
import { EVENTS_SOCKETS } from 'src/constants/sockets';
import { useSocket } from 'src/contexts/SocketContext';
import {
  FullScreenElementType,
  LivestreamPollAnsweredEvent,
  PollResponse,
  PollStatus,
  Poll as PollType,
} from 'src/types/stream';
import { useLokaliseTranslation } from 'src/utils/i18n';

import {
  getPollPercentage,
  getPollStatus,
  getSelectedPollOptionId,
} from '../../utils';
import { fullScreenCommentWidth } from '../CustomParticipantView';

type PollProps = {
  poll: PollType;
  pollService: {
    vote: (pollId: number, pollOptionId: number) => Promise<AxiosResponse>;
    key: Array<string | number>;
  };
  toggleFullscreen: () => void;
  fullScreenElement: FullScreenElementType;
  isCaptionsOpen?: boolean;
  isHls?: boolean;
};

const Poll: FC<PollProps> = props => {
  const {
    poll,
    pollService,
    isCaptionsOpen,
    isHls,
    toggleFullscreen,
    fullScreenElement,
  } = props;

  const { t } = useLokaliseTranslation('livestream');
  const theme = useTheme();
  const socket = useSocket();

  const [isPollOpen, setIsPollOpen] = useState(
    fullScreenElement !== FullScreenElementType.NONE,
  );

  const pollStatus = getPollStatus(
    poll.pollConfiguration.startsAt,
    poll.pollConfiguration.endsAt,
  );

  const form = useForm({
    defaultValues: {
      selectedOption: poll.pollOptions.reduce(
        (acc, option) => {
          acc[option.id] = option.isLoggedUserAnswer;
          return acc;
        },
        {} as Record<string, boolean>,
      ),
    },
  });

  useEffect(() => {
    const handlePollAnswered = (event: LivestreamPollAnsweredEvent) => {
      if (event.pollId === poll.id) {
        queryClient.invalidateQueries(pollService.key);
      }
    };

    socket.listenEvent(
      EVENTS_SOCKETS.LIVESTREAM_POLL_ANSWERED,
      handlePollAnswered,
    );

    return () => {
      socket.closeEvent(
        EVENTS_SOCKETS.LIVESTREAM_POLL_ANSWERED,
        handlePollAnswered,
      );
    };
  }, [socket, poll.id, pollService.key]);

  const voteMutation = useMutation(
    (variables: { pollId: number; pollOptionId: number }) =>
      pollService.vote(variables.pollId, variables.pollOptionId),
    {
      onSuccess: () => {
        queryClient.setQueryData<AxiosResponse<PollResponse> | undefined>(
          pollService.key,
          oldData => {
            if (!oldData || !oldData.data.poll) return oldData;

            return {
              ...oldData,
              data: {
                poll: {
                  ...oldData.data.poll,
                  hasBeenAnswered: true,
                  totalAnswerCount: oldData.data.poll.totalAnswerCount + 1,
                  pollOptions: oldData.data.poll.pollOptions.map(option =>
                    option.id ===
                    getSelectedPollOptionId(form.getValues('selectedOption'))
                      ? { ...option, answerCount: option.answerCount + 1 }
                      : option,
                  ),
                },
              },
            };
          },
        );
        queryClient.invalidateQueries(pollService.key);
      },
    },
  );

  const iconPosition = isCaptionsOpen
    ? {
        top: 16,
        right:
          fullScreenElement === FullScreenElementType.SEMI
            ? fullScreenCommentWidth + 16
            : 16,
      }
    : {
        left:
          fullScreenElement === FullScreenElementType.SEMI
            ? `calc(50% - ${fullScreenCommentWidth / 2}px)`
            : '50%',
        bottom: isHls ? 56 : 16,
        transform: 'translateX(-50%)',
      };

  const handlePollIconClick = () => {
    setIsPollOpen(true);
    if (fullScreenElement === FullScreenElementType.NONE) {
      toggleFullscreen();
    }
  };

  const handleVoteClick = form.handleSubmit(() => {
    const selectedOptionId = getSelectedPollOptionId(
      form.getValues('selectedOption'),
    );
    if (!selectedOptionId) return;
    voteMutation.mutate({
      pollId: poll.id,
      pollOptionId: selectedOptionId,
    });
  });

  if (isPollOpen) {
    return (
      <FormProvider {...form}>
        <CardContainer
          sx={{
            position: 'absolute',
            width: 'auto',
            minWidth: '500px',
            maxWidth: {
              md: '672px',
              lg: '840px',
            },
            bottom: 16,
            zIndex: 2,
            left:
              fullScreenElement === FullScreenElementType.SEMI
                ? `calc(50% - ${fullScreenCommentWidth / 2}px)`
                : '50%',
            transform: 'translateX(-50%)',
            '& > .MuiCardContent-root': {
              display: 'flex',
              flexDirection: 'column',
              gap: 2,
              px: 0,
              py: 1,
            },
          }}
        >
          <Stack
            sx={{
              flexDirection: 'row',
              alignItems: 'center',
              justifyContent: 'space-between',
              px: 3,
            }}
          >
            <Typography
              variant={
                pollStatus === PollStatus.ACTIVE ? 'globalXS' : 'globalS'
              }
              fontWeight="fontWeightSemiBold"
              color="new.text.neutral.default"
            >
              {pollStatus === PollStatus.ACTIVE && poll.title}
              {pollStatus === PollStatus.ENDED &&
                t('polls.viewer_results.finished')}
            </Typography>
            <IconButton onClick={() => setIsPollOpen(false)}>
              <IconX />
            </IconButton>
          </Stack>
          <Grid
            container
            spacing={1.5}
            sx={{ px: 3 }}
          >
            {pollStatus === PollStatus.ACTIVE &&
              poll.pollOptions.map(option => (
                <Grid
                  key={option.id}
                  item
                  xs={6}
                  sx={{ wordBreak: 'break-word' }}
                >
                  <FormSelectionCard
                    name={`selectedOption.${option.id}`}
                    disabled={poll.hasBeenAnswered}
                    isOnlyOption
                    sx={{
                      width: '100%',
                      height: '100%',
                      '& > .MuiCardContent-root': {
                        display: 'flex',
                        alignItems: 'center',
                        justifyContent: 'space-between',
                        cursor: 'default',
                        backgroundColor: theme.palette.newBase?.white,
                      },
                    }}
                  >
                    <RadioButton
                      label={option.option}
                      isActive={form.watch(`selectedOption.${option.id}`)}
                      disabled={poll.hasBeenAnswered}
                      size="small"
                      labelProps={{
                        variant: 'globalXS',
                      }}
                      stackSx={{
                        cursor: 'default',
                        '& > .MuiStack-root': {
                          cursor: 'default',
                        },
                      }}
                    />
                    {poll.hasBeenAnswered &&
                      poll.pollConfiguration.viewVotesResult && (
                        <Typography
                          variant="globalXS"
                          color="new.text.neutral.lighter"
                        >
                          {getPollPercentage(
                            option.answerCount,
                            poll.totalAnswerCount,
                          )}
                          %
                        </Typography>
                      )}
                  </FormSelectionCard>
                </Grid>
              ))}
            {pollStatus === PollStatus.ENDED &&
              poll.pollOptions.map(option => (
                <Grid
                  key={option.id}
                  item
                  xs={6}
                >
                  <ProgressBar
                    variant="determinate"
                    title={option.option}
                    current={option.answerCount}
                    total={poll.totalAnswerCount || 100}
                    hasPercentage
                    withEllipsis
                    sx={{
                      '& .MuiStack-root:first-of-type .MuiTypography-root': {
                        color: theme.palette.new.text.neutral.default,
                        fontWeight: 'regular',
                      },
                    }}
                  />
                </Grid>
              ))}
          </Grid>
          {pollStatus === PollStatus.ACTIVE && (
            <Stack
              sx={{
                alignItems: 'flex-end',
                pt: 1.5,
                px: 2,
                pb: 0.5,
                borderTop: `1px solid ${theme.palette.new.border.neutral.default}`,
              }}
            >
              <Button
                variant="primary"
                size="small"
                disabled={!form.formState.isDirty || poll.hasBeenAnswered}
                loading={voteMutation.isLoading}
                onClick={handleVoteClick}
              >
                {t('polls.vote')}
              </Button>
            </Stack>
          )}
        </CardContainer>
      </FormProvider>
    );
  }

  return (
    <Stack
      onClick={handlePollIconClick}
      sx={{
        ...iconPosition,
        position: 'absolute',
        backgroundColor:
          theme.palette.new.action.button.background.primary.default,
        borderRadius: '50%',
        p: 1.5,
        cursor: 'pointer',
        zIndex: 2,
        '& svg': {
          color: theme.palette.new.text.neutral.inverted,
        },
      }}
    >
      <IconChartBarPopular />
    </Stack>
  );
};

export default Poll;
