import { css } from '@emotion/css';
import * as React from 'react';

import {
  type GrafanaTheme2,
  dateTimeFormat,
  systemDateFormats,
  textUtil,
  type LinkModel,
  type ActionModel,
} from '@grafana/data';
import { t } from '@grafana/i18n';
import { Stack, IconButton, Tag, usePanelContext, useStyles2 } from '@grafana/ui';
import { VizTooltipFooter } from '@grafana/ui/internal';
import alertDef from 'app/features/alerting/state/alertDef';

import { AnnotationTooltipHeaderCloseIcon } from './AnnotationTooltipHeaderCloseIcon';

interface Props {
  annoVals: Record<string, any[]>;
  annoIdx: number;
  timeZone: string;
  isPinned: boolean;
  onClose: () => void;
  onEdit: () => void;
  links?: LinkModel[];
  actions?: ActionModel[];
}

const retFalse = () => false;

export const AnnotationTooltip2 = ({
  annoVals,
  annoIdx,
  timeZone,
  isPinned,
  onClose,
  onEdit,
  links = [],
  actions = [],
}: Props) => {
  const annoId = annoVals.id?.[annoIdx];

  const styles = useStyles2(getStyles);
  const focusRef = React.useRef<HTMLButtonElement | null>(null);
  const { canEditAnnotations = retFalse, canDeleteAnnotations = retFalse, onAnnotationDelete } = usePanelContext();
  const dashboardUID = annoVals.dashboardUID?.[annoIdx];

  // grafana can be configured to load alert rules from loki. Those annotations cannot be edited or deleted. The id being 0 is the best indicator the annotation came from loki
  const canEdit = annoId !== 0 && canEditAnnotations(dashboardUID);
  const canDelete = annoId !== 0 && canDeleteAnnotations(dashboardUID) && onAnnotationDelete != null;

  React.useEffect(() => {
    if (isPinned) {
      focusRef.current?.focus();
    }
  }, [isPinned]);

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

  let time = timeFormatter(annoVals.time[annoIdx]);
  let text = annoVals.text?.[annoIdx] ?? '';

  if (annoVals.isRegion?.[annoIdx]) {
    time += ' - ' + timeFormatter(annoVals.timeEnd[annoIdx]);
  }

  let avatar;
  if (annoVals.login?.[annoIdx] && annoVals.avatarUrl?.[annoIdx]) {
    avatar = <img className={styles.avatar} alt="Annotation avatar" src={annoVals.avatarUrl[annoIdx]} />;
  }

  let state: React.ReactNode | null = null;
  let alertText = '';

  if (annoVals.alertId?.[annoIdx] !== undefined && annoVals.newState?.[annoIdx]) {
    const stateModel = alertDef.getStateDisplayModel(annoVals.newState[annoIdx]);
    state = (
      <div className={styles.alertState}>
        <i className={stateModel.stateClass}>{stateModel.text}</i>
      </div>
    );

    alertText = annoVals.data?.[annoIdx] ? alertDef.getAlertAnnotationText(annoVals.data[annoIdx]) : '';
  } else if (annoVals.title?.[annoIdx]) {
    text = annoVals.title[annoIdx] + (text ? `<br />${text}` : '');
  }

  return (
    <div className={styles.wrapper}>
      <div className={styles.header}>
        <Stack gap={2} basis="100%" justifyContent="space-between" alignItems="center">
          <div className={styles.meta}>
            <span>
              {avatar}
              {state}
            </span>
            {time}
          </div>
          {(canEdit || canDelete || isPinned) && (
            <div className={styles.controls}>
              {canEdit && (
                <IconButton
                  ref={focusRef}
                  name={'pen'}
                  size={'sm'}
                  onClick={onEdit}
                  tooltip={t('timeseries.annotation-tooltip2.tooltip-edit', 'Edit')}
                />
              )}
              {canDelete && (
                <IconButton
                  ref={canEdit ? null : focusRef}
                  name={'trash-alt'}
                  size={'sm'}
                  onClick={() => onAnnotationDelete(annoId)}
                  tooltip={t('timeseries.annotation-tooltip2.tooltip-delete', 'Delete')}
                />
              )}
              {isPinned && (
                <AnnotationTooltipHeaderCloseIcon
                  forwardRef={canEdit || canDelete ? null : focusRef}
                  onClick={(e) => {
                    // Don't trigger onClick
                    e.stopPropagation();
                    onClose();
                  }}
                />
              )}
            </div>
          )}
        </Stack>
      </div>

      <div className={styles.body}>
        {text && <div className={styles.text} dangerouslySetInnerHTML={{ __html: textUtil.sanitize(text) }} />}
        {alertText}
        <div>
          <Stack gap={0.5} wrap={true}>
            {annoVals.tags?.[annoIdx]?.map((t: string, i: number) => (
              <Tag data-testid={'annotation-tag'} name={t} key={`${t}-${i}`} />
            ))}
          </Stack>
        </div>
      </div>

      {(links.length > 0 || actions.length > 0) && <VizTooltipFooter dataLinks={links} actions={actions} />}
    </div>
  );
};

const getStyles = (theme: GrafanaTheme2) => ({
  wrapper: css({
    zIndex: theme.zIndex.tooltip,
    whiteSpace: 'initial',
    borderRadius: theme.shape.radius.default,
    background: theme.colors.background.elevated,
    border: `1px solid ${theme.colors.border.weak}`,
    boxShadow: theme.shadows.z3,
    userSelect: 'text',
  }),
  header: css({
    padding: theme.spacing(0.5, 1),
    borderBottom: `1px solid ${theme.colors.border.weak}`,
    fontWeight: theme.typography.fontWeightBold,
    fontSize: theme.typography.fontSize,
    color: theme.colors.text.primary,
    display: 'flex',
  }),
  meta: css({
    display: 'flex',
    color: theme.colors.text.primary,
    fontWeight: 400,
  }),
  controls: css({
    display: 'flex',
    '> :last-child': {
      marginLeft: 0,
    },
  }),
  body: css({
    padding: theme.spacing(1),
    fontSize: theme.typography.bodySmall.fontSize,
    color: theme.colors.text.secondary,
    fontWeight: 400,
    a: {
      color: theme.colors.text.link,
      '&:hover': {
        textDecoration: 'underline',
      },
    },
  }),
  text: css({
    paddingBottom: theme.spacing(1),
  }),
  avatar: css({
    borderRadius: theme.shape.radius.circle,
    width: 16,
    height: 16,
    marginRight: theme.spacing(1),
  }),
  alertState: css({
    paddingRight: theme.spacing(1),
    fontWeight: theme.typography.fontWeightMedium,
  }),
});
