import { css } from '@emotion/css';
import { useRef, useEffect } from 'react';
import { Controller } from 'react-hook-form';
import { useAsyncFn, useClickAway } from 'react-use';

import { type AnnotationEventUIModel, type GrafanaTheme2, dateTimeFormat, systemDateFormats } from '@grafana/data';
import { Trans, t } from '@grafana/i18n';
import { Button, Field, Stack, TextArea, usePanelContext, useStyles2 } from '@grafana/ui';
import { Form } from 'app/core/components/Form/Form';
import { TagFilter } from 'app/core/components/TagFilter/TagFilter';
import { annotationServer } from 'app/features/annotations/api';

import { AnnotationTooltipHeaderCloseIcon } from './AnnotationTooltipHeaderCloseIcon';

interface Props {
  annoVals: Record<string, any[]>;
  annoIdx: number;
  timeZone: string;
  dismiss: () => void;
}

interface AnnotationEditFormDTO {
  description: string;
  tags: string[];
}

export const AnnotationEditor2 = ({ annoVals, annoIdx, dismiss, timeZone, ...otherProps }: Props) => {
  const styles = useStyles2(getStyles);
  const { onAnnotationCreate, onAnnotationUpdate } = usePanelContext();
  const focusRef = useRef<HTMLButtonElement | null>(null);
  const clickAwayRef = useRef(null);

  useClickAway(clickAwayRef, dismiss);

  // focus text area on render
  useEffect(() => {
    focusRef.current?.focus();
  }, []);

  const [createAnnotationState, createAnnotation] = useAsyncFn(async (event: AnnotationEventUIModel) => {
    const result = await onAnnotationCreate!(event);
    dismiss();
    return result;
  });

  const [updateAnnotationState, updateAnnotation] = useAsyncFn(async (event: AnnotationEventUIModel) => {
    const result = await onAnnotationUpdate!(event);
    dismiss();
    return result;
  });

  const timeFormatter = (value: number) =>
    dateTimeFormat(value, {
      format: systemDateFormats.fullDate,
      timeZone,
    });

  const isUpdatingAnnotation = annoVals.id?.[annoIdx] != null;
  const isRegionAnnotation = annoVals.isRegion?.[annoIdx];
  const operation = isUpdatingAnnotation ? updateAnnotation : createAnnotation;
  const stateIndicator = isUpdatingAnnotation ? updateAnnotationState : createAnnotationState;
  const time = isRegionAnnotation
    ? `${timeFormatter(annoVals.time[annoIdx])} - ${timeFormatter(annoVals.timeEnd[annoIdx])}`
    : timeFormatter(annoVals.time[annoIdx]);

  const onSubmit = ({ tags, description }: AnnotationEditFormDTO) => {
    operation({
      id: annoVals.id?.[annoIdx] ?? undefined,
      tags,
      description,
      from: Math.round(annoVals.time[annoIdx]!),
      to: Math.round(annoVals.timeEnd?.[annoIdx] ?? annoVals.time[annoIdx]!),
    });
  };

  // Annotation editor
  return (
    <div ref={clickAwayRef} className={styles.editor} {...otherProps}>
      <div className={styles.header}>
        <Stack justifyContent={'space-between'} alignItems={'center'}>
          <Stack gap={0} width="100%" justifyContent={'space-between'} alignItems={'center'}>
            <div>
              {isUpdatingAnnotation
                ? t('timeseries.annotation-editor2.edit-annotation', 'Edit annotation')
                : t('timeseries.annotation-editor2.add-annotation', 'Add annotation')}
            </div>
            <div>{time}</div>
          </Stack>
          <AnnotationTooltipHeaderCloseIcon
            forwardRef={focusRef}
            onClick={(e) => {
              // Don't trigger onClick
              e.stopPropagation();
              dismiss();
            }}
          />
        </Stack>
      </div>
      <Form<AnnotationEditFormDTO>
        onSubmit={onSubmit}
        defaultValues={{ description: annoVals.text?.[annoIdx], tags: annoVals.tags?.[annoIdx] || [] }}
      >
        {({ register, errors, control }) => {
          return (
            <>
              <div className={styles.content}>
                <Field
                  label={t('timeseries.annotation-editor2.label-description', 'Description')}
                  invalid={!!errors.description}
                  error={errors?.description?.message}
                >
                  <TextArea
                    data-testid={'annotation-editor-description'}
                    className={styles.textarea}
                    {...register('description', {
                      required: 'Annotation description is required',
                    })}
                  />
                </Field>
                <Field label={t('timeseries.annotation-editor2.label-tags', 'Tags')}>
                  <Controller
                    control={control}
                    name="tags"
                    render={({ field: { ref, onChange, ...field } }) => {
                      return (
                        <TagFilter
                          allowCustomValue
                          placeholder={t('timeseries.annotation-editor2.placeholder-add-tags', 'Add tags')}
                          onChange={onChange}
                          tagOptions={annotationServer().tags}
                          tags={field.value}
                        />
                      );
                    }}
                  />
                </Field>
              </div>
              <div className={styles.footer}>
                <Stack justifyContent={'flex-end'}>
                  <Button size={'sm'} variant="secondary" onClick={dismiss} fill="outline">
                    <Trans i18nKey="timeseries.annotation-editor2.cancel">Cancel</Trans>
                  </Button>
                  <Button size={'sm'} type={'submit'} disabled={stateIndicator?.loading}>
                    {stateIndicator?.loading
                      ? t('timeseries.annotation-editor2.saving', 'Saving')
                      : t('timeseries.annotation-editor2.save', 'Save')}
                  </Button>
                </Stack>
              </div>
            </>
          );
        }}
      </Form>
    </div>
  );
};

const getStyles = (theme: GrafanaTheme2) => {
  return {
    editor: css({
      background: theme.colors.background.elevated,
      border: `1px solid ${theme.colors.border.weak}`,
      borderRadius: theme.shape.radius.default,
      boxShadow: theme.shadows.z3,
      userSelect: 'text',
      width: '460px',
    }),
    content: css({
      padding: theme.spacing(1),
    }),
    header: css({
      borderBottom: `1px solid ${theme.colors.border.weak}`,
      padding: theme.spacing(0.5, 1),
      fontWeight: theme.typography.fontWeightBold,
      fontSize: theme.typography.fontSize,
      color: theme.colors.text.primary,
    }),
    footer: css({
      borderTop: `1px solid ${theme.colors.border.weak}`,
      padding: theme.spacing(1, 1),
    }),
    textarea: css({
      color: theme.colors.text.secondary,
      fontSize: theme.typography.bodySmall.fontSize,
    }),
  };
};
