import {Fragment, useContext, useEffect, useRef} from 'react';
import styled from '@emotion/styled';

import FormContext from 'sentry/components/forms/formContext';
import type {FieldValue} from 'sentry/components/forms/model';
import Panel from 'sentry/components/panels/panel';
import Placeholder from 'sentry/components/placeholder';
import {t} from 'sentry/locale';
import {useApiQuery} from 'sentry/utils/queryClient';
import {useDimensions} from 'sentry/utils/useDimensions';
import useOrganization from 'sentry/utils/useOrganization';
import {ScheduleType} from 'sentry/views/monitors/types';

import {CheckInPlaceholder} from './timeline/checkInPlaceholder';
import {MockCheckInTimeline} from './timeline/checkInTimeline';
import {GridLineLabels, GridLineOverlay} from './timeline/gridLines';
import {getConfigFromTimeRange} from './timeline/utils/getConfigFromTimeRange';

interface ScheduleConfig {
  cronSchedule?: FieldValue;
  intervalFrequency?: FieldValue;
  intervalUnit?: FieldValue;
  scheduleType?: FieldValue;
  timezone?: FieldValue;
}

const NUM_SAMPLE_TICKS = 9;

function isValidConfig(schedule: ScheduleConfig) {
  const {scheduleType, cronSchedule, intervalFrequency, intervalUnit} = schedule;
  return !!(
    (scheduleType === ScheduleType.CRONTAB && cronSchedule) ||
    (scheduleType === ScheduleType.INTERVAL && intervalFrequency && intervalUnit)
  );
}

interface Props {
  schedule: ScheduleConfig;
}

export function MockTimelineVisualization({schedule}: Props) {
  const {scheduleType, cronSchedule, timezone, intervalFrequency, intervalUnit} =
    schedule;

  const organization = useOrganization();
  const {form} = useContext(FormContext);

  const query = {
    num_ticks: NUM_SAMPLE_TICKS,
    schedule_type: scheduleType,
    timezone,
    schedule:
      scheduleType === 'interval' ? [intervalFrequency, intervalUnit] : cronSchedule,
  };

  const elementRef = useRef<HTMLDivElement>(null);
  const {width: timelineWidth} = useDimensions<HTMLDivElement>({elementRef});

  const sampleDataQueryKey = [
    `/organizations/${organization.slug}/monitors-schedule-data/`,
    {query},
  ] as const;
  const {data, isLoading, isError, error} = useApiQuery<number[]>(sampleDataQueryKey, {
    staleTime: 0,
    enabled: isValidConfig(schedule),
    retry: false,
  });

  const errorMessage =
    isError || !isValidConfig(schedule)
      ? error?.responseJSON?.schedule?.[0] ?? t('Invalid Schedule')
      : null;

  useEffect(() => {
    if (!form) {
      return;
    }

    if (scheduleType === ScheduleType.INTERVAL) {
      form.setError('config.schedule.frequency', errorMessage);
    } else if (scheduleType === ScheduleType.CRONTAB) {
      form.setError('config.schedule', errorMessage);
    }
  }, [errorMessage, form, scheduleType]);

  const mockTimestamps = data?.map(ts => new Date(ts * 1000));
  const start = mockTimestamps?.[0];
  const end = mockTimestamps?.[mockTimestamps.length - 1];
  const timeWindowConfig =
    start && end ? getConfigFromTimeRange(start, end, timelineWidth) : undefined;

  return (
    <TimelineContainer>
      <TimelineWidthTracker ref={elementRef} />
      {isLoading || !start || !end || !timeWindowConfig || !mockTimestamps ? (
        <Fragment>
          <Placeholder height="50px" />
          {errorMessage ? null : <CheckInPlaceholder />}
        </Fragment>
      ) : (
        <Fragment>
          <AlignedGridLineLabels timeWindowConfig={timeWindowConfig} />
          <AlignedGridLineOverlay
            showCursor={!isLoading}
            timeWindowConfig={timeWindowConfig}
          />
          <MockCheckInTimeline
            mockTimestamps={mockTimestamps.slice(1, mockTimestamps.length - 1)}
            timeWindowConfig={timeWindowConfig}
          />
        </Fragment>
      )}
    </TimelineContainer>
  );
}

const TimelineContainer = styled(Panel)`
  display: grid;
  grid-template-columns: 1fr;
  grid-template-rows: auto 60px;
  align-items: center;
`;

const AlignedGridLineLabels = styled(GridLineLabels)`
  grid-column: 0;
  border-bottom: 1px solid ${p => p.theme.border};
`;

const AlignedGridLineOverlay = styled(GridLineOverlay)`
  grid-column: 0;
`;

const TimelineWidthTracker = styled('div')`
  position: absolute;
  width: 100%;
  grid-row: 1;
  grid-column: 0;
`;
