import { css } from '@emotion/css';
import { useEffect, useMemo, useState } from 'react';

import { rangeUtil, SelectableValue } from '@grafana/data';
import { t } from '@grafana/i18n';
import { SceneComponentProps, sceneGraph } from '@grafana/scenes';
import { ConditionalRenderingTimeRangeSizeKind } from '@grafana/schema/dist/esm/schema/dashboard/v2alpha1/types.spec.gen';
import { Field, Select, useStyles2 } from '@grafana/ui';

import { ConditionalRenderingBase, ConditionalRenderingBaseState } from './ConditionalRenderingBase';
import { ConditionalRenderingSerializerRegistryItem, TimeRangeSizeConditionValue } from './types';

type ConditionalRenderingTimeRangeSizeState = ConditionalRenderingBaseState<TimeRangeSizeConditionValue>;

export class ConditionalRenderingTimeRangeSize extends ConditionalRenderingBase<ConditionalRenderingTimeRangeSizeState> {
  public static Component = ConditionalRenderingTimeRangeSizeRenderer;

  public static serializer: ConditionalRenderingSerializerRegistryItem = {
    id: 'ConditionalRenderingTimeRangeSize',
    name: 'Time Range Size',
    deserialize: this.deserialize,
  };

  public get title(): string {
    return t('dashboard.conditional-rendering.conditions.time-range-size.label', 'Time range less than');
  }

  public get info(): string {
    return t(
      'dashboard.conditional-rendering.conditions.time-range-size.info',
      'Show or hide the {{type}} if the dashboard time range is shorter than the selected time frame.',
      { type: this.getItemType() }
    );
  }

  public constructor(state: ConditionalRenderingTimeRangeSizeState) {
    super(state);

    this.addActivationHandler(() => this._activationHandler());
  }

  private _activationHandler() {
    this._subs.add(sceneGraph.getTimeRange(this).subscribeToState(() => this.notifyChange()));
  }

  public evaluate(): boolean {
    try {
      if (!validateIntervalRegex.test(this.state.value)) {
        return true;
      }

      const interval = rangeUtil.intervalToSeconds(this.state.value);
      const timeRange = sceneGraph.getTimeRange(this);

      if (timeRange.state.value.to.unix() - timeRange.state.value.from.unix() <= interval) {
        return true;
      }
    } catch {
      return false;
    }

    return false;
  }

  public serialize(): ConditionalRenderingTimeRangeSizeKind {
    return { kind: 'ConditionalRenderingTimeRangeSize', spec: { value: this.state.value } };
  }

  public static deserialize(model: ConditionalRenderingTimeRangeSizeKind): ConditionalRenderingTimeRangeSize {
    return new ConditionalRenderingTimeRangeSize({ value: model.spec.value });
  }

  public static createEmpty(): ConditionalRenderingTimeRangeSize {
    return new ConditionalRenderingTimeRangeSize({ value: '7d' });
  }
}

function ConditionalRenderingTimeRangeSizeRenderer({ model }: SceneComponentProps<ConditionalRenderingTimeRangeSize>) {
  const { value } = model.useState();
  const [isValid, setIsValid] = useState(validateIntervalRegex.test(value));
  const styles = useStyles2(getStyles);

  useEffect(() => setIsValid(validateIntervalRegex.test(value)), [value]);

  const staticOptions = useMemo<Array<SelectableValue<string>>>(
    () => [
      {
        label: t('dashboard.conditional-rendering.conditions.time-range-size.values.minutes', '{{value}} minutes', {
          value: 5,
        }),
        value: '5m',
      },
      {
        label: t('dashboard.conditional-rendering.conditions.time-range-size.values.minutes', '{{value}} minutes', {
          value: 15,
        }),
        value: '15m',
      },
      {
        label: t('dashboard.conditional-rendering.conditions.time-range-size.values.minutes', '{{value}} minutes', {
          value: 30,
        }),
        value: '30m',
      },
      {
        label: t('dashboard.conditional-rendering.conditions.time-range-size.values.hour', '{{value}} hour', {
          value: 1,
        }),
        value: '1h',
      },
      {
        label: t('dashboard.conditional-rendering.conditions.time-range-size.values.hours', '{{value}} hours', {
          value: 3,
        }),
        value: '3h',
      },
      {
        label: t('dashboard.conditional-rendering.conditions.time-range-size.values.hours', '{{value}} hours', {
          value: 6,
        }),
        value: '6h',
      },
      {
        label: t('dashboard.conditional-rendering.conditions.time-range-size.values.hours', '{{value}} hours', {
          value: 12,
        }),
        value: '12h',
      },
      {
        label: t('dashboard.conditional-rendering.conditions.time-range-size.values.hours', '{{value}} hours', {
          value: 24,
        }),
        value: '24h',
      },
      {
        label: t('dashboard.conditional-rendering.conditions.time-range-size.values.days', '{{value}} days', {
          value: 2,
        }),
        value: '2d',
      },
      {
        label: t('dashboard.conditional-rendering.conditions.time-range-size.values.days', '{{value}} days', {
          value: 7,
        }),
        value: '7d',
      },
      {
        label: t('dashboard.conditional-rendering.conditions.time-range-size.values.days', '{{value}} days', {
          value: 30,
        }),
        value: '30d',
      },
      {
        label: t('dashboard.conditional-rendering.conditions.time-range-size.values.days', '{{value}} days', {
          value: 90,
        }),
        value: '90d',
      },
      {
        label: t('dashboard.conditional-rendering.conditions.time-range-size.values.months', '{{value}} months', {
          value: 6,
        }),
        value: '6M',
      },
      {
        label: t('dashboard.conditional-rendering.conditions.time-range-size.values.year', '{{value}} year', {
          value: 1,
        }),
        value: '1y',
      },
      {
        label: t('dashboard.conditional-rendering.conditions.time-range-size.values.years', '{{value}} years', {
          value: 2,
        }),
        value: '2y',
      },
      {
        label: t('dashboard.conditional-rendering.conditions.time-range-size.values.years', '{{value}} years', {
          value: 5,
        }),
        value: '5y',
      },
    ],
    []
  );

  const options = useMemo(() => {
    if (staticOptions.find((option) => option.value === value)) {
      return staticOptions;
    }

    return [{ label: value, value }, ...staticOptions];
  }, [staticOptions, value]);

  return (
    <Field
      invalid={!isValid}
      error={t('dashboard.conditional-rendering.conditions.time-range-size.invalid-message', 'Invalid interval')}
      className={styles.container}
    >
      <Select
        isClearable={false}
        allowCustomValue
        onCreateOption={(value) => model.setStateAndNotify({ value })}
        value={value}
        options={options}
        onChange={({ value }) => model.setStateAndNotify({ value })}
      />
    </Field>
  );
}

const getStyles = () => ({
  container: css({
    margin: 0,
  }),
});

const validateIntervalRegex = /^(\d+(?:\.\d+)?)[Mwdhmsy]$/;
