import logWebUserEvent from '@/logging/logWebUserEvent';

import { getAnalyticsToolName } from '../EditModeContext';
import { getEditCategory } from '../SelectionContext';
import { CanvasRegion } from './CanvasRenderer';
import { EditCanvasRenderContext } from './EditCanvasRenderContext';

const SELECTION_X_WIDTH = 14;
const SELECTION_Y_HEIGHT = 6;
const HALF_SELECTION_Y_HEIGHT = SELECTION_Y_HEIGHT / 2;
const CORNER_CENTER_OFFSET = SELECTION_X_WIDTH - HALF_SELECTION_Y_HEIGHT;
let draggingEdge = false;
const makeMainSelectionRegion = ({
  selectionY,
  selectionHeight,
  selectionStartX,
  selectionEndX,
  editMode,
  alignedLyricsFocused,
}: EditCanvasRenderContext) => ({
  touchTarget:
    editMode === 'remove'
      ? {
          bounds: {
            top: selectionY,
            bottom: selectionY + selectionHeight,
            left: selectionStartX - SELECTION_X_WIDTH,
            right: selectionEndX + SELECTION_X_WIDTH,
          },
        }
      : undefined,
  render: (ctx: CanvasRenderingContext2D, hovered: boolean) => {
    const width = selectionEndX - selectionStartX;

    if (editMode === 'remove') {
      ctx.fillStyle = '#521F1F' + (hovered || draggingEdge ? '44' : 'aa');
      ctx.beginPath();
      ctx.roundRect(
        selectionStartX,
        selectionY + HALF_SELECTION_Y_HEIGHT,
        width,
        selectionHeight - SELECTION_Y_HEIGHT,
        SELECTION_X_WIDTH / 2
      );

      ctx.closePath();
      ctx.fill();

      if (width > 40) {
        ctx.fillStyle = '#ffffff';
        ctx.textAlign = 'center';
        ctx.textBaseline = 'middle';
        ctx.font = '40px "Input Sans", monospace';
        ctx.fillText(
          '⃠',
          selectionStartX + width / 2,
          selectionY + selectionHeight / 2
        );
      }
    }

    if (
      alignedLyricsFocused ||
      (editMode === 'remove' && (draggingEdge || hovered))
    ) {
      ctx.fillStyle = '#ffffff44';
    } else {
      ctx.fillStyle = '#ffffffff';
    }
    ctx.beginPath();

    ctx.moveTo(
      selectionStartX,
      selectionY + selectionHeight + HALF_SELECTION_Y_HEIGHT
    );
    ctx.arc(
      selectionStartX,
      selectionY + selectionHeight - CORNER_CENTER_OFFSET,
      SELECTION_X_WIDTH,
      0.5 * Math.PI,
      Math.PI
    );
    ctx.lineTo(selectionStartX - SELECTION_X_WIDTH, selectionY);
    ctx.arc(
      selectionStartX,
      selectionY + CORNER_CENTER_OFFSET,
      SELECTION_X_WIDTH,
      Math.PI,
      1.5 * Math.PI
    );

    ctx.moveTo(selectionStartX + width + SELECTION_X_WIDTH, selectionY);
    ctx.arc(
      selectionStartX + width,
      selectionY + CORNER_CENTER_OFFSET,
      SELECTION_X_WIDTH,
      2 * Math.PI,
      1.5 * Math.PI,
      true
    );
    ctx.lineTo(
      selectionStartX + width,
      selectionY + selectionHeight + HALF_SELECTION_Y_HEIGHT
    );
    ctx.arc(
      selectionStartX + width,
      selectionY + selectionHeight - CORNER_CENTER_OFFSET,
      SELECTION_X_WIDTH,
      0.5 * Math.PI,
      0,
      true
    );

    ctx.rect(
      selectionStartX,
      selectionY - HALF_SELECTION_Y_HEIGHT,
      width,
      SELECTION_Y_HEIGHT
    );
    ctx.rect(
      selectionStartX,
      selectionY + selectionHeight - HALF_SELECTION_Y_HEIGHT,
      width,
      SELECTION_Y_HEIGHT
    );

    // top left corner
    ctx.moveTo(selectionStartX, selectionY + HALF_SELECTION_Y_HEIGHT);
    ctx.lineTo(selectionStartX, selectionY + 8);
    ctx.arc(selectionStartX + 5, selectionY + 8, 5, Math.PI, 1.5 * Math.PI);
    ctx.lineTo(selectionStartX, selectionY + HALF_SELECTION_Y_HEIGHT);

    // top right corner
    ctx.moveTo(selectionStartX + width, selectionY + HALF_SELECTION_Y_HEIGHT);
    ctx.lineTo(selectionStartX + width, selectionY + 8);
    ctx.arc(
      selectionStartX + width - 5,
      selectionY + 8,
      5,
      0,
      1.5 * Math.PI,
      true
    );
    ctx.lineTo(selectionStartX + width, selectionY + HALF_SELECTION_Y_HEIGHT);

    // bottom right corner
    ctx.moveTo(selectionStartX + width, selectionY + selectionHeight - 8);
    ctx.lineTo(
      selectionStartX + width,
      selectionY + selectionHeight - HALF_SELECTION_Y_HEIGHT
    );
    ctx.arc(
      selectionStartX + width - 5,
      selectionY + selectionHeight - 8,
      5,
      Math.PI * 0.5,
      0,
      true
    );
    ctx.lineTo(selectionStartX + width, selectionY + selectionHeight - 8);

    // bottom left corner
    ctx.moveTo(selectionStartX, selectionY + selectionHeight - 8);
    ctx.lineTo(
      selectionStartX,
      selectionY + selectionHeight - HALF_SELECTION_Y_HEIGHT
    );
    ctx.arc(
      selectionStartX + 5,
      selectionY + selectionHeight - 8,
      5,
      Math.PI * 0.5,
      Math.PI
    );
    ctx.lineTo(selectionStartX, selectionY + selectionHeight - 8);

    ctx.closePath();
    ctx.fill();

    if (editMode === 'fadeOut') {
      ctx.strokeStyle = '#ffffff';
      ctx.fillStyle = `rgba(255,255,255,0.1)`;
      ctx.beginPath();
      ctx.moveTo(selectionStartX, selectionY + 3);
      ctx.bezierCurveTo(
        selectionStartX + width * 0.25,
        selectionY + 3,
        selectionStartX + width * 0.75,
        selectionY + selectionHeight - 3,
        selectionStartX + width,
        selectionY + selectionHeight - 3
      );
      ctx.lineTo(selectionStartX, selectionY + selectionHeight - 3);
      ctx.closePath();
      ctx.stroke();
      ctx.fill();

      ctx.fillStyle = `rgba(0,0,0,0.6)`;
      ctx.beginPath();
      ctx.moveTo(selectionStartX, selectionY + 3);
      ctx.bezierCurveTo(
        selectionStartX + width * 0.25,
        selectionY + 3,
        selectionStartX + width * 0.75,
        selectionY + selectionHeight - 3,
        selectionStartX + width,
        selectionY + selectionHeight - 3
      );
      ctx.lineTo(selectionStartX + width, selectionY + 3);
      ctx.closePath();
      ctx.fill();
    }

    if (getEditCategory(editMode) === 'end-fixed') {
      ctx.beginPath();
      ctx.fillStyle = '#ffffff';
      ctx.moveTo(selectionStartX, selectionY + selectionHeight / 2 - 10);
      ctx.lineTo(selectionStartX + 10, selectionY + selectionHeight / 2);
      ctx.lineTo(selectionStartX, selectionY + selectionHeight / 2 + 10);
      ctx.closePath();
      ctx.fill();
    }
  },
});

const makeSelectionStartRegion = ({
  selectionY,
  selectionHeight,
  selectionStartX,
  handleClickDrag,
  editMode,
  editSessionId,
  clipId,
  setSelectionStartSeconds,
  selectionEndSeconds,
  snapToBeat,
  frameCountRef,
}: EditCanvasRenderContext): CanvasRegion => {
  return {
    touchTarget: {
      bounds: {
        top: selectionY,
        bottom: selectionY + selectionHeight,
        left: selectionStartX - SELECTION_X_WIDTH,
        right: selectionStartX,
      },
      hoverCursor: 'ew-resize',
      dragCursor: 'ew-resize',
      onMouseDown: handleClickDrag(({ downSeconds }) => {
        let lastMoveSeconds = downSeconds;
        frameCountRef.current++;
        draggingEdge = true;
        return {
          onMouseMove: ({ moveSeconds }) => {
            setSelectionStartSeconds(
              editMode === 'remove' ? snapToBeat(moveSeconds) : moveSeconds,
              true
            );
            lastMoveSeconds = moveSeconds;
          },
          onMouseUp: () => {
            draggingEdge = false;
            setSelectionStartSeconds(
              editMode === 'remove'
                ? snapToBeat(lastMoveSeconds)
                : lastMoveSeconds,
              true
            );
            logWebUserEvent({
              actionName: 'MakeWaveformSelection',
              context: {
                startSeconds: lastMoveSeconds,
                endSeconds: selectionEndSeconds,
                editTool: getAnalyticsToolName(editMode),
                editSessionId: editSessionId || 'MISSING_EDIT_SESSION_ID',
                editingClipId: clipId,
                actionIndex: -1, // todo?
                inputType: 'timeline-start-drag',
              },
            });
          },
        };
      }),
    },
    render: (ctx, hovered) => {
      ctx.fillStyle = hovered || draggingEdge ? '#00000077' : '#00000055';
      ctx.beginPath();
      ctx.roundRect(
        selectionStartX - SELECTION_X_WIDTH / 2 - 2,
        selectionY + selectionHeight / 2 - 15,
        4,
        30,
        2
      );
      ctx.closePath();
      ctx.fill();
    },
  };
};

const makeSelectionEndRegion = ({
  selectionY,
  selectionHeight,
  selectionEndX,
  handleClickDrag,
  editMode,
  editSessionId,
  clipId,
  setSelectionEndSeconds,
  selectionStartSeconds,
  snapToBeat,
  frameCountRef,
}: EditCanvasRenderContext): CanvasRegion => {
  return {
    touchTarget: {
      bounds: {
        top: selectionY,
        bottom: selectionY + selectionHeight,
        left: selectionEndX,
        right: selectionEndX + SELECTION_X_WIDTH,
      },
      hoverCursor: 'ew-resize',
      dragCursor: 'ew-resize',
      onMouseDown: handleClickDrag(({ downSeconds }) => {
        draggingEdge = true;
        frameCountRef.current++;
        let lastMoveSeconds = downSeconds;
        return {
          onMouseMove: ({ moveSeconds }) => {
            if (getEditCategory(editMode) === 'fluid') {
              setSelectionEndSeconds(
                editMode === 'remove' ? snapToBeat(moveSeconds) : moveSeconds,
                true
              );
              lastMoveSeconds = moveSeconds;
            }
          },
          onMouseUp: () => {
            draggingEdge = false;
            if (getEditCategory(editMode) === 'fluid') {
              setSelectionEndSeconds(
                editMode === 'remove'
                  ? snapToBeat(lastMoveSeconds)
                  : lastMoveSeconds,
                true
              );
              logWebUserEvent({
                actionName: 'MakeWaveformSelection',
                context: {
                  startSeconds: selectionStartSeconds,
                  endSeconds: lastMoveSeconds,
                  editTool: getAnalyticsToolName(editMode),
                  editSessionId: editSessionId || 'MISSING_EDIT_SESSION_ID',
                  editingClipId: clipId,
                  actionIndex: -1, // todo?
                  inputType: 'timeline-end-drag',
                },
              });
            }
          },
        };
      }),
    },
    render: (ctx, hovered) => {
      ctx.fillStyle = hovered || draggingEdge ? '#00000077' : '#00000055';
      ctx.beginPath();
      ctx.roundRect(
        selectionEndX + SELECTION_X_WIDTH / 2 - 2,
        selectionY + selectionHeight / 2 - 15,
        4,
        30,
        2
      );
      ctx.closePath();
      ctx.fill();
    },
  };
};

const makeSelectionLineRegion = ({
  selectionY,
  selectionHeight,
  selectionStartX,
  handleClickDrag,
  editMode,
  editSessionId,
  clipId,
  setSelectionStartSeconds,
  snapToBeat,
  frameCountRef,
  selectionEndSeconds,
  timelineWrapperRect,
}: EditCanvasRenderContext): CanvasRegion => {
  return {
    touchTarget: {
      bounds: {
        top: 0,
        bottom: timelineWrapperRect.height,
        left: selectionStartX - 10,
        right: selectionStartX + 10,
      },
      hoverCursor: 'ew-resize',
      dragCursor: 'ew-resize',
      onMouseDown: handleClickDrag(({ downSeconds }) => {
        let lastMoveSeconds = downSeconds;
        frameCountRef.current++;
        draggingEdge = true;
        return {
          onMouseMove: ({ moveSeconds }) => {
            setSelectionStartSeconds(
              editMode === 'remove' ? snapToBeat(moveSeconds) : moveSeconds,
              true
            );
            lastMoveSeconds = moveSeconds;
          },
          onMouseUp: () => {
            draggingEdge = false;
            setSelectionStartSeconds(
              editMode === 'remove'
                ? snapToBeat(lastMoveSeconds)
                : lastMoveSeconds,
              true
            );
            logWebUserEvent({
              actionName: 'MakeWaveformSelection',
              context: {
                startSeconds: lastMoveSeconds,
                endSeconds: selectionEndSeconds,
                editTool: getAnalyticsToolName(editMode),
                editSessionId: editSessionId || 'MISSING_EDIT_SESSION_ID',
                editingClipId: clipId,
                actionIndex: -1, // todo?
                inputType: 'timeline-start-drag',
              },
            });
          },
        };
      }),
    },
    render: (ctx) => {
      ctx.fillStyle = '#00000055';
      ctx.rect(
        selectionStartX - 1,
        0,
        timelineWrapperRect.width - selectionStartX,
        timelineWrapperRect.height
      );
      ctx.fill();
      ctx.fillStyle = '#ffffffff';
      ctx.beginPath();
      ctx.rect(selectionStartX - 1, 0, 2, timelineWrapperRect.height);
      ctx.closePath();
      ctx.moveTo(selectionStartX, selectionY + selectionHeight / 2 - 10);
      ctx.lineTo(selectionStartX + 10, selectionY + selectionHeight / 2);
      ctx.lineTo(selectionStartX, selectionY + selectionHeight / 2 + 10);
      ctx.closePath();
      ctx.fill();
    },
  };
};

export default function makeSelectionRegions(
  context: EditCanvasRenderContext
): CanvasRegion[] {
  const canSelectEnd = getEditCategory(context.editMode) !== 'end-fixed';
  if (!canSelectEnd) {
    return [makeSelectionLineRegion(context)];
  } else {
    return [
      makeMainSelectionRegion(context),
      makeSelectionStartRegion(context),
      makeSelectionEndRegion(context),
    ];
  }
}
