import { css } from '@emotion/css';
import { DragDropContext, Draggable, type DraggableProvided, Droppable, type DropResult } from '@hello-pangea/dnd';
import { useCallback } from 'react';

import { type GrafanaTheme2 } from '@grafana/data';
import { t } from '@grafana/i18n';
import { Card, IconButton, useStyles2 } from '@grafana/ui';

import { useLogDetailsContext } from './LogDetailsContext';
import { type LogLineDetailsMode } from './LogLineDetails';
import { useLogListContext } from './LogListContext';
import { reportInteractionOnce } from './analytics';
import { getNormalizedFieldName } from './processing';

export const LogLineDetailsDisplayedFields = () => {
  const { displayedFields, setDisplayedFields } = useLogListContext();

  const reorganizeDisplayedFields = useCallback(
    (srcIndex: number, destIndex: number, mode: 'drag' | 'button') => {
      const newDisplayedFields = [...displayedFields];
      const element = displayedFields[srcIndex];

      newDisplayedFields.splice(srcIndex, 1);
      newDisplayedFields.splice(destIndex, 0, element);

      setDisplayedFields?.(newDisplayedFields);

      reportInteractionOnce('logs_log_line_details_organized_fields', {
        quantity: newDisplayedFields.length,
        mode,
      });
    },
    [displayedFields, setDisplayedFields]
  );

  const onDragEnd = useCallback(
    (result: DropResult) => {
      if (result.destination == null) {
        return;
      }
      reorganizeDisplayedFields(result.source.index, result.destination.index, 'drag');
    },
    [reorganizeDisplayedFields]
  );

  return (
    <div>
      <DragDropContext onDragEnd={onDragEnd}>
        <Droppable droppableId="displayed-fields" direction="vertical">
          {(provided) => {
            return (
              <div ref={provided.innerRef} {...provided.droppableProps}>
                {displayedFields.map((field, index) => (
                  <DraggableDisplayedField
                    key={field}
                    field={field}
                    index={index}
                    moveField={reorganizeDisplayedFields}
                  />
                ))}
                {provided.placeholder}
              </div>
            );
          }}
        </Droppable>
      </DragDropContext>
    </div>
  );
};

interface DraggableDisplayedFieldProps {
  field: string;
  index: number;
  moveField: (srcIndex: number, destIndex: number, mode: 'drag' | 'button') => void;
}

const DraggableDisplayedField = ({ field, index, moveField }: DraggableDisplayedFieldProps) => {
  return (
    <Draggable draggableId={field} index={index}>
      {(provided) => (
        <DisplayedField key={field} field={field} index={index} moveField={moveField} provided={provided} />
      )}
    </Draggable>
  );
};

const DisplayedField = ({
  field,
  index,
  moveField,
  provided,
}: DraggableDisplayedFieldProps & { provided: DraggableProvided }) => {
  const { displayedFields, onClickHideField } = useLogListContext();
  const { detailsMode } = useLogDetailsContext();
  const styles = useStyles2(getStyles, detailsMode);
  const nextIndex = index === displayedFields.length - 1 ? 0 : index + 1;
  const prevIndex = index === 0 ? displayedFields.length - 1 : index - 1;
  return (
    <div ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}>
      <Card noMargin className={styles.fieldCard}>
        <div className={styles.fieldWrapper}>
          <div className={styles.field}>{getNormalizedFieldName(field)}</div>
          {displayedFields.length > 1 && (
            <>
              <IconButton
                name="arrow-down"
                onClick={() => moveField(index, nextIndex, 'button')}
                tooltip={t('logs.log-line-details.move-displayed-field-down', 'Move down')}
              />
              <IconButton
                name="arrow-up"
                onClick={() => moveField(index, prevIndex, 'button')}
                tooltip={t('logs.log-line-details.move-displayed-field-up', 'Move up')}
              />
            </>
          )}
          {onClickHideField && (
            <IconButton
              name="times"
              onClick={() => onClickHideField(field)}
              tooltip={t('logs.log-line-details.remove-displayed-field', 'Remove field')}
            />
          )}
        </div>
      </Card>
    </div>
  );
};

const getStyles = (theme: GrafanaTheme2, detailsMode: LogLineDetailsMode) => ({
  fieldCard: css({
    display: 'block',
    padding: theme.spacing(1),
    marginBottom: theme.spacing(1),
    width: detailsMode === 'inline' ? '30vw' : undefined,
    overflow: 'hidden',
    textOverflow: 'ellipsis',
    wordBreak: 'break-word',
  }),
  fieldWrapper: css({
    cursor: 'move',
    display: 'flex',
    gap: theme.spacing(0.5),
    justifyContent: 'space-evenly',
  }),
  field: css({
    flex: 1,
  }),
});
