import React, { useEffect, useRef, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import classNames from 'clsx';
import dayjs from 'dayjs';
import { CalendarToday, InfoOutlined, NearMeOutlined, TrendingDown, TrendingUp } from '@mui/icons-material';

import { CALENDAR_FILTER, CALENDAR_FILTER_VALUE, ORIGIN_FILTER, TABS } from '../constants';
import {
  WIDGET_DISPLAY_STATE_DATA,
  WIDGET_DISPLAY_STATE_ERROR,
  WIDGET_DISPLAY_STATE_NO_DATA,
} from '@/modules/analytics/common/constants';

import * as selectors from '../redux/selectors';
import * as actions from '../redux/slices';
import { abbreviateNumber } from '@/modules/@common/helpers/number';

import {
  AreaGraph,
  DialogCalendarRange,
  GlobalStateEmpty,
  GlobalStateError,
  Header,
  Layout,
  RoundItemContainer,
} from '@/modules/analytics/common/components';
import Stub from '@/modules/analytics/common/components/Stub';
import TopSearches from './TopSearches';
import VideoGraph from './VideoGraph';
import VideoSearch from './VideoSearch';
import VideoTable from './VideoTable';
import {
  Autocomplete,
  FormControlLabel,
  Grid,
  InputAdornment,
  MenuItem,
  Rating,
  Select,
  Switch,
  TextField,
  ToggleButton,
  ToggleButtonGroup,
  Tooltip,
  Typography,
} from '@/mui/components';

import styles from './VideoContentPerfomance.module.scss';

function VideoContentPerformance() {
  const dispatch = useDispatch();

  const hub = useSelector(selectors.hubSelector);
  const hubOptions = useSelector(selectors.hubOptionsSelector);
  const watch = useSelector(selectors.watchSelector);
  const watchOptions = useSelector(selectors.watchOptionsSelector);
  const watchChannel = useSelector(selectors.watchChannelSelector);
  const watchChannelOptions = useSelector(selectors.watchChannelOptionsSelector);
  const origin = useSelector(selectors.originSelector);
  const calendar = useSelector(selectors.calendarSelector);
  const calendarCustom = useSelector(selectors.calendarCustomSelector);
  const includeArchived = useSelector(selectors.includeArchivedSelector);
  const activeTabId = useSelector(selectors.activeTabIdSelector);
  const total = useSelector(selectors.totalSelector);
  const topSearches = useSelector(selectors.topSearchesSelector);
  const tableItems = useSelector(selectors.tableItemsSelector);
  const search = useSelector(selectors.searchSelector);
  const searchOptions = useSelector(selectors.searchOptionsSelector);
  const sortBy = useSelector(selectors.sortBySelector);
  const sortOrder = useSelector(selectors.sortOrderSelector);
  const metrics = useSelector(selectors.metricsSelector);
  const metricViews = useSelector(selectors.metricViewsSelector);
  const metricAttentionSpan = useSelector(selectors.metricAttentionSpanSelector);
  const metricSearches = useSelector(selectors.metricSearchesSelector);
  const selectedItemId = useSelector(selectors.selectedItemIdSelector);
  const activeMetric = useSelector(selectors.activeMetricSelector);
  const itemMetrics = useSelector(selectors.itemMetricsSelector);
  const displayStateMainMetrics = useSelector(selectors.displayStateMainMetricsSelector);
  const displayStateTopSearches = useSelector(selectors.displayStateTopSearchesSelector);
  const displayStateTopVideos = useSelector(selectors.displayStateTopVideosSelector);
  const isExportCsvLoading = useSelector(selectors.isExportCsvLoadingSelector);
  const isExportPdfLoading = useSelector(selectors.isExportPdfLoadingSelector);
  const shouldShowGlobalNoDataState = useSelector(selectors.getGlobalNoDataState);
  const shouldShowGlobalErrorState = useSelector(selectors.getGlobalErrorState);

  const setField = (o) => dispatch(actions.setFieldAction(o));
  const getSearchOptions = (o) => dispatch(actions.getSearchOptionsAction(o));
  const getItemMetrics = (o) => dispatch(actions.getItemMetricsAction(o));
  const exportToCsv = (o) => dispatch(actions.exportToCsvAction(o));

  const [isCalendarOpen, setIsCalendarOpen] = useState(false);
  const contentRef = useRef(null);

  const handleSearchAndSorting = (params) => {
    dispatch(actions.getTableItemsAction({ total: false, exactMatch: !!params?.exactMatch }));
  };

  const fetchData = () => {
    dispatch(actions.getTableItemsAction());
    dispatch(actions.getPerformanceTopSearchesAction());
    dispatch(actions.getPerformanceVideosTotalAction());
    dispatch(
      actions.getPerformanceVideosTotalMetricAction({
        metric: 'NO_OF_VIEWS',
        key: 'metricViews',
      }),
    );
    dispatch(
      actions.getPerformanceVideosTotalMetricAction({
        metric: 'ATTENTION_SPAN',
        key: 'metricAttentionSpan',
      }),
    );
    dispatch(
      actions.getPerformanceVideosTotalMetricAction({
        metric: 'SEARCHES',
        key: 'metricSearches',
      }),
    );
  };

  useEffect(() => {
    fetchData();
  }, []);

  // export handlers
  const handleExportToPdf = () => dispatch(actions.exportToPdfAction(contentRef.current));

  // filters handlers
  const handleFilterSetHub = (filter) => {
    dispatch(
      actions.setFieldAction({
        hub: filter,
        watch: null,
        watchChannel: null,
        search: null,
      }),
    );

    fetchData();
  };

  const handleFilterSetWatch = (filter) => {
    dispatch(
      actions.setFieldAction({
        watch: filter,
        watchChannel: null,
        watchChannelOptions: watch?.channels ?? [],
        search: null,
      }),
    );

    fetchData();
  };

  const handleFilterSetWatchChannel = (filter) => {
    dispatch(
      actions.setFieldAction({
        watchChannel: filter,
        search: null,
      }),
    );

    fetchData();
  };

  const handleFilterSetCalendar = (filter) => {
    dispatch(
      actions.setFieldAction({
        calendar: filter,
        search: null,
      }),
    );

    if (filter === CALENDAR_FILTER_VALUE.custom) {
      setIsCalendarOpen(true);
      return;
    }

    fetchData();
  };

  const handleMenuItemClick = (itemValue) => {
    if (itemValue === CALENDAR_FILTER_VALUE.custom) {
      setIsCalendarOpen(true);
    }
  };

  const defineGraphSecondLegend = () => {
    if (watchChannel) {
      return 'Channel avg.';
    }

    if (watch) {
      return 'Watch avg.';
    }

    if (hub) {
      return 'Hub avg.';
    }

    return 'Account avg.';
  };

  const defineMainWidgetState = (totalValue, chartData) => {
    if (displayStateMainMetrics === WIDGET_DISPLAY_STATE_ERROR) {
      return displayStateMainMetrics;
    }

    if (totalValue !== null || chartData?.length) {
      return WIDGET_DISPLAY_STATE_DATA;
    }

    return WIDGET_DISPLAY_STATE_NO_DATA;
  };

  const handleTabChange = (id) => {
    dispatch(
      setField({
        activeTabId: id,
        search: null,
        searchOptions: [],
      }),
    );
    dispatch(actions.getTableItemsAction());
  };

  const selectedVideo = tableItems?.find((item) => item?.uuid === selectedItemId);

  return (
    <Layout ref={contentRef}>
      <Header
        onExportToPdf={handleExportToPdf}
        onExportToCsv={exportToCsv}
        isExportCsvLoading={isExportCsvLoading}
        isExportPdfLoading={isExportPdfLoading}
        disabledExport={shouldShowGlobalNoDataState || shouldShowGlobalErrorState}
      >
        Video Performance
      </Header>

      <Grid container justifyContent="space-between" alignItems="center" className={styles.FilterWrapper}>
        <Grid item container alignItems="center" className={styles.FilterLeftSection}>
          <Grid item className={styles.FilterItem}>
            <Autocomplete
              id="site"
              value={hub}
              options={hubOptions || []}
              loading={!hubOptions}
              size="small"
              onChange={(e, hubValue) => handleFilterSetHub(hubValue)}
              onOpen={() => dispatch(actions.getHubOptionsAction(''))}
              renderInput={(params) => (
                <TextField
                  {...params}
                  data-id="hub"
                  value=""
                  variant="outlined"
                  size="small"
                  placeholder="Select Hub"
                />
              )}
            />
          </Grid>

          <Grid item className={styles.FilterItem}>
            <Autocomplete
              id="watch"
              value={watch}
              options={watchOptions || []}
              loading={!watchOptions}
              disabled={!hub?.value}
              size="small"
              onChange={(e, watchValue) => handleFilterSetWatch(watchValue)}
              onOpen={() => dispatch(actions.getWatchOptionsAction(''))}
              renderInput={(params) => (
                <TextField {...params} data-id="hub" value="" variant="outlined" placeholder="Select Watch" />
              )}
            />
          </Grid>
          <Grid item className={styles.FilterItem}>
            <Autocomplete
              id="watch-channel"
              value={watchChannel}
              options={watchChannelOptions || []}
              loading={!watchOptions}
              disabled={!watch?.value}
              size="small"
              onChange={(e, watchChannelValue) => handleFilterSetWatchChannel(watchChannelValue)}
              renderInput={(params) => (
                <TextField {...params} data-id="hub" value="" variant="outlined" placeholder="Select Channel" />
              )}
            />
          </Grid>
          <Grid item className={classNames(styles.FilterItem, styles.FilterItem___noWidth)}>
            <span className={styles.FilterTotal}>{`Videos: ${total}`}</span>
          </Grid>

          <div className={styles.SwitchWrapper}>
            <FormControlLabel
              control={
                <Switch
                  color="primary"
                  size="xSmall"
                  checked={includeArchived}
                  onChange={({ target }) => {
                    dispatch(
                      actions.setFieldAction({
                        includeArchived: target.checked,
                      }),
                    );
                    fetchData();
                  }}
                />
              }
              label="Include archived videos"
              labelPlacement="end"
            />
          </div>
        </Grid>
        <Grid item container justifyContent="flex-end" className={styles.FilterRightSection}>
          <Grid item className={styles.FilterItemAdditional}>
            <Select
              autoWidth
              value={origin}
              data-id="origin-select"
              variant="outlined"
              size="small"
              startAdornment={
                <InputAdornment position="start">
                  <NearMeOutlined color="info" />
                </InputAdornment>
              }
              onChange={({ target }) => {
                dispatch(
                  setField({
                    origin: target.value,
                    search: null,
                  }),
                );

                fetchData();
              }}
            >
              {ORIGIN_FILTER.map((item) => (
                <MenuItem value={item.value} key={item.value}>
                  {item.label}
                </MenuItem>
              ))}
            </Select>
          </Grid>
          <Grid item className={styles.FilterItemAdditional}>
            <Select
              autoWidth
              value={calendar}
              renderValue={
                calendar === CALENDAR_FILTER_VALUE.custom && calendarCustom?.dateStart && calendarCustom?.dateEnd
                  ? () =>
                      `${dayjs(calendarCustom.dateStart).format('DD/MM')} - ${dayjs(calendarCustom.dateEnd).format('DD/MM')}`
                  : false
              }
              data-id="origin-select"
              variant="outlined"
              size="small"
              startAdornment={
                <InputAdornment position="start">
                  <CalendarToday color="info" />
                </InputAdornment>
              }
              onChange={({ target }) => handleFilterSetCalendar(target.value)}
            >
              {CALENDAR_FILTER.map((item) => (
                <MenuItem key={item.value} value={item.value} onClick={() => handleMenuItemClick(item.value)}>
                  {item.label}
                </MenuItem>
              ))}
            </Select>
          </Grid>
        </Grid>
      </Grid>

      {shouldShowGlobalNoDataState && <GlobalStateEmpty />}
      {shouldShowGlobalErrorState && <GlobalStateError />}
      {!shouldShowGlobalNoDataState && !shouldShowGlobalErrorState && (
        <div className={styles.WidgetsContainer}>
          <RoundItemContainer
            displayState={defineMainWidgetState(metrics?.total?.numOfViews, metricViews)}
            type="horizontal"
            size="small"
            item
          >
            <div className={styles.Metric}>
              <div className={styles.MetricHeader}>
                <Typography variant="caption" color="text.primary" fontWeight={500}>
                  Views
                </Typography>
                <Tooltip title="The number of times videos have been played" placement="top">
                  <InfoOutlined htmlColor="info.main" />
                </Tooltip>
              </div>
              <div className={styles.MetricContent}>
                <div className={styles.MetricInfo}>
                  <Typography variant="h4" color="primary.main" fontWeight={400}>
                    {abbreviateNumber(metrics?.total?.numOfViews) ?? 'N/A'}
                  </Typography>

                  {!!metrics?.comparison?.numOfViews && (
                    <div>
                      {metrics?.comparison?.numOfViews >= 0 ? (
                        <TrendingUp fontSize="medium" color="success" />
                      ) : (
                        <TrendingDown fontSize="medium" color="error" />
                      )}

                      {!metrics?.hideComparisonNumbers && (
                        <Typography
                          className={styles.MetricPercent}
                          variant="caption"
                          color={metrics?.comparison?.numOfViews >= 0 ? 'success.main' : 'error.main'}
                          fontWeight={400}
                        >
                          {`${metrics?.comparison?.numOfViews > 0 ? '+' : ''}${Math.round(metrics?.comparison?.numOfViews ?? 0)}%`}
                        </Typography>
                      )}
                    </div>
                  )}
                </div>
                <div className={styles.MetricGraph}>
                  <AreaGraph
                    data={metricViews}
                    stroke="#9B61F3"
                    gradient="areaGradient2"
                    tooltipDateFormatter={
                      calendar === CALENDAR_FILTER_VALUE.custom
                        ? calendarCustom.tooltipDateFormatter
                        : calendar.tooltipDateFormatter
                    }
                  />
                </div>
              </div>
            </div>
          </RoundItemContainer>

          <RoundItemContainer
            displayState={defineMainWidgetState(metrics?.total?.attentionSpan, metricAttentionSpan)}
            type="horizontal"
            size="small"
            item
          >
            <div className={styles.Metric}>
              <div className={styles.MetricHeader}>
                <Typography variant="caption" color="text.primary" fontWeight={500}>
                  Attention Span
                </Typography>
                <Tooltip title="Video completion rate in %" placement="top">
                  <InfoOutlined htmlColor="info.main" />
                </Tooltip>
              </div>
              <div className={styles.MetricContent}>
                <div className={styles.MetricInfo}>
                  <Typography variant="h4" color="primary.main" fontWeight={400}>
                    {`${metrics?.total?.attentionSpan?.toFixed(1) ?? ''}%`}
                  </Typography>

                  {!!metrics?.comparison?.attentionSpan && (
                    <div>
                      {metrics?.comparison?.attentionSpan >= 0 ? (
                        <TrendingUp fontSize="medium" color="success" />
                      ) : (
                        <TrendingDown fontSize="medium" color="error" />
                      )}

                      {!metrics?.hideComparisonNumbers && (
                        <Typography
                          className={styles.MetricPercent}
                          variant="caption"
                          color={metrics?.comparison?.attentionSpan >= 0 ? 'success.main' : 'error.main'}
                          fontWeight={400}
                        >
                          {`${metrics?.comparison?.attentionSpan > 0 ? '+' : ''}${Math.round(metrics?.comparison?.attentionSpan ?? 0)}%`}
                        </Typography>
                      )}
                    </div>
                  )}
                </div>
                <div className={styles.MetricGraph}>
                  <AreaGraph
                    data={metricAttentionSpan}
                    stroke="#6E9EFA"
                    tooltipDateFormatter={
                      calendar === CALENDAR_FILTER_VALUE.custom
                        ? calendarCustom.tooltipDateFormatter
                        : calendar.tooltipDateFormatter
                    }
                  />
                </div>
              </div>
            </div>
          </RoundItemContainer>

          <RoundItemContainer
            displayState={defineMainWidgetState(metrics?.total?.engScore)}
            type="horizontal"
            size="small"
          >
            <div className={styles.Metric}>
              <div className={styles.MetricHeader}>
                <Typography variant="caption" color="text.primary" fontWeight={500}>
                  Engagement Score
                </Typography>
                <Tooltip title="A score calculation (0-5) based on users' actions with a video" placement="top">
                  <InfoOutlined htmlColor="info.main" />
                </Tooltip>
              </div>
              <div className={styles.MetricContent}>
                <div className={classNames(styles.MetricInfo, styles.MetricInfo___withRating)}>
                  <Typography variant="h4" color="primary.main" fontWeight={400}>
                    {metrics?.total?.engScore?.toFixed(1)}
                  </Typography>

                  {!!metrics?.comparison?.engScore && (
                    <div>
                      {metrics?.comparison?.engScore >= 0 ? (
                        <TrendingUp fontSize="medium" color="success" />
                      ) : (
                        <TrendingDown fontSize="medium" color="error" />
                      )}

                      {!metrics?.hideComparisonNumbers && (
                        <Typography
                          className={styles.MetricPercent}
                          variant="caption"
                          color={metrics?.comparison?.engScore >= 0 ? 'success.main' : 'error.main'}
                          fontWeight={400}
                        >
                          {`${metrics?.comparison?.engScore > 0 ? '+' : ''}${Math.round(metrics?.comparison?.engScore ?? 0)}%`}
                        </Typography>
                      )}
                    </div>
                  )}
                </div>
                <div className={styles.MetricRating}>
                  <Rating
                    name="engScore"
                    size="large"
                    value={Number(metrics?.total?.engScore?.toFixed(1) ?? 0)}
                    precision={0.5}
                    readOnly
                    color="warning"
                  />
                </div>
              </div>
            </div>
          </RoundItemContainer>

          <RoundItemContainer
            displayState={defineMainWidgetState(metrics?.total?.searches, metricSearches)}
            type="horizontal"
            size="small"
            item
          >
            <div className={styles.Metric}>
              <div className={styles.MetricHeader}>
                <Typography variant="caption" color="text.primary" fontWeight={500}>
                  Searches
                </Typography>
                <Tooltip title="Total number of searches" placement="top">
                  <InfoOutlined htmlColor="info.main" />
                </Tooltip>
              </div>
              <div className={styles.MetricContent}>
                <div className={styles.MetricInfo}>
                  <Typography variant="h4" color="primary.main" fontWeight={400}>
                    {abbreviateNumber(metrics?.total?.searches) ?? 'N/A'}
                  </Typography>

                  {!!metrics?.comparison?.searches && (
                    <div>
                      {metrics?.comparison?.searches >= 0 ? (
                        <TrendingUp fontSize="medium" color="success" />
                      ) : (
                        <TrendingDown fontSize="medium" color="error" />
                      )}

                      {!metrics?.hideComparisonNumbers && (
                        <Typography
                          className={styles.MetricPercent}
                          variant="caption"
                          color={metrics?.comparison?.searches >= 0 ? 'success.main' : 'error.main'}
                          fontWeight={400}
                        >
                          {`${metrics?.comparison?.searches > 0 ? '+' : ''}${Math.round(metrics?.comparison?.searches ?? 0)}%`}
                        </Typography>
                      )}
                    </div>
                  )}
                </div>
                <div className={styles.MetricGraph}>
                  <AreaGraph
                    data={metricSearches}
                    stroke="#24B321"
                    gradient="areaGradient3"
                    tooltipDateFormatter={
                      calendar === CALENDAR_FILTER_VALUE.custom
                        ? calendarCustom.tooltipDateFormatter
                        : calendar.tooltipDateFormatter
                    }
                  />
                </div>
              </div>
            </div>
          </RoundItemContainer>

          <RoundItemContainer
            displayState={WIDGET_DISPLAY_STATE_DATA}
            size="large"
            container
            className={styles.VideoTableContainer}
          >
            <Grid container>
              <Grid
                item
                xs={7}
                className={classNames(styles.Info, {
                  [styles.Info___empty]: !tableItems?.length,
                })}
              >
                <div className={styles.VideoTableWrapper}>
                  <ToggleButtonGroup
                    className={styles.Tabs}
                    value={activeTabId}
                    exclusive
                    color="neutral"
                    size="xSmall"
                    onChange={(event, newState) => {
                      if (newState) {
                        handleTabChange(newState);
                      }
                    }}
                  >
                    {TABS.map((tab) => (
                      <ToggleButton key={tab.id} value={tab.id}>
                        {tab.title}
                      </ToggleButton>
                    ))}
                  </ToggleButtonGroup>
                  <VideoSearch
                    search={search}
                    searchOptions={searchOptions}
                    setField={setField}
                    getSearchOptions={getSearchOptions}
                    handleSearchAndSorting={handleSearchAndSorting}
                  />

                  {!!tableItems?.length && (
                    <VideoTable
                      tableItems={tableItems}
                      sortBy={sortBy}
                      sortOrder={sortOrder}
                      setField={setField}
                      selectedItemId={selectedItemId}
                      activeTabId={activeTabId}
                      handleSearchAndSorting={handleSearchAndSorting}
                      getItemMetrics={getItemMetrics}
                    />
                  )}
                </div>
              </Grid>

              {!!tableItems?.length && selectedVideo && (
                <Grid item xs={5} className={styles.VideoTableGraphWrapper}>
                  <VideoGraph
                    selectedItemId={selectedItemId}
                    selectedVideo={selectedVideo}
                    activeMetric={activeMetric}
                    itemMetrics={itemMetrics}
                    setField={setField}
                    getItemMetrics={getItemMetrics}
                    videoChartDataKey={
                      calendar === CALENDAR_FILTER_VALUE.custom
                        ? calendarCustom?.videoChartDataKey
                        : calendar?.videoChartDataKey
                    }
                    comparisonLegend={defineGraphSecondLegend()}
                    tooltipDateFormatter={
                      calendar === CALENDAR_FILTER_VALUE.custom
                        ? calendarCustom.tooltipGraphDateFormatter
                        : calendar.tooltipGraphDateFormatter
                    }
                    activeTabId={activeTabId}
                  />
                </Grid>
              )}

              {!tableItems?.length && (
                <Grid item xs={12} className={styles.VideoTableEmptyContainer}>
                  <Stub
                    imageType={WIDGET_DISPLAY_STATE_NO_DATA}
                    type="vertical"
                    size="large"
                    firstTitle={
                      displayStateTopVideos === WIDGET_DISPLAY_STATE_NO_DATA
                        ? 'No Data...'
                        : 'No Search Results found...'
                    }
                    firstSubTitle={
                      displayStateTopVideos === WIDGET_DISPLAY_STATE_NO_DATA
                        ? 'No Data matching selected filters.'
                        : 'We can`t find any item matching your search.'
                    }
                    secondSubTitle={
                      displayStateTopVideos === WIDGET_DISPLAY_STATE_NO_DATA
                        ? 'Try adjusting your filters.'
                        : 'Please try again.'
                    }
                  />
                </Grid>
              )}
            </Grid>
          </RoundItemContainer>

          <RoundItemContainer displayState={displayStateTopSearches}>
            <div className={styles.TopSearches}>
              <div className={classNames(styles.MetricHeader, styles.TopSearchesHeader)}>
                <Typography variant="caption" color="text.primary" fontWeight={500}>
                  Top Searches
                </Typography>
                <Tooltip title="Top searches performed by amount and % out of the total searches" placement="top">
                  <InfoOutlined htmlColor="info.main" />
                </Tooltip>
              </div>

              <div className={styles.TopSearchesContent}>
                <TopSearches data={topSearches} />
              </div>
            </div>
          </RoundItemContainer>
        </div>
      )}

      <DialogCalendarRange
        open={isCalendarOpen}
        onClose={() => setIsCalendarOpen(false)}
        onDateSubmit={(dateRange) => {
          const diff = dayjs(dateRange.dateEnd).diff(dateRange.dateStart, 'days');
          const isMoreThanOneDay = diff > 1;

          dispatch(
            actions.setFieldAction({
              search: null,
              calendarCustom: {
                ...dateRange,
                tooltipDateFormatter: isMoreThanOneDay
                  ? (value) => value.format('MMM DD')
                  : (value) => value.format('hh A'),
                tooltipGraphDateFormatter: isMoreThanOneDay
                  ? (value) => value.format('MMM DD, YYYY')
                  : (value) => value.format('hh:mm A'),
              },
            }),
          );

          setIsCalendarOpen(false);

          fetchData();
        }}
      />
    </Layout>
  );
}

export default VideoContentPerformance;
