import { CanvasRegion } from '@/components/edit2025/canvasRenderer/CanvasRenderer';

import { StudioContextType } from '../StudioContext';
import { CLIP_CORNER_RADIUS } from '../constants';
import getCanvasRelativeRect from '../getCanvasRelativeRect';
import { EDGE_TOUCH_TARGET_WIDTH } from './makeStudioSelectionRegions';

export const makeFadeInRegions = (
  studioContext: StudioContextType,
  trackId: string,
  fadeInStartBeats: number,
  fadeDurationBeats: number,
  updateFadeInFlight: (delta: number) => void,
  updateFadeState: (delta: number) => void,
  dragKey: string
): CanvasRegion[] => {
  const trackHeader =
    studioContext.timelineController.trackHeadersRef.current[trackId];
  if (!trackHeader) return [];

  const trackHeaderRect = getCanvasRelativeRect(
    trackHeader.getBoundingClientRect(),
    studioContext.timelineController.getWrapperRect()
  );

  const fadeInEndBeats =
    fadeInStartBeats +
    (fadeDurationBeats + studioContext.inFlightDrags.get(dragKey));
  const fadeInEndX = studioContext.beatsToCanvasX(fadeInEndBeats);
  const fadeInStartX = studioContext.beatsToCanvasX(fadeInStartBeats);
  const fadeInTopY = trackHeaderRect.top;
  const fadeInBottomY = trackHeaderRect.bottom;
  const fadeInWidth = fadeInEndX - fadeInStartX;
  const fadeInHeight = fadeInBottomY - fadeInTopY;
  const fadeInMiddleX = (fadeInStartX + fadeInEndX) / 2;

  return [
    {
      touchTarget: {
        bounds: {
          top: fadeInTopY,
          bottom: fadeInBottomY,
          left: fadeInStartX,
          right: fadeInEndX,
        },
        passthrough: true,
        hoverGroup: dragKey,
      },

      renderTop: (ctx: CanvasRenderingContext2D, hovered: boolean) => {
        ctx.save();
        ctx.roundRect(
          fadeInStartX,
          fadeInTopY,
          fadeInWidth,
          fadeInHeight,
          CLIP_CORNER_RADIUS
        );
        ctx.clip();
        ctx.beginPath();
        ctx.strokeStyle = 'rgba(255,255,255,1.0)';
        ctx.fillStyle = 'rgba(0,0,0,0.2)';
        ctx.moveTo(fadeInStartX, fadeInBottomY);
        ctx.lineTo(fadeInStartX, fadeInTopY);
        ctx.lineTo(fadeInEndX, fadeInTopY);
        ctx.bezierCurveTo(
          fadeInMiddleX,
          fadeInTopY,
          fadeInMiddleX,
          fadeInBottomY,
          fadeInStartX,
          fadeInBottomY
        );
        ctx.fill();

        ctx.save();
        ctx.beginPath();
        ctx.roundRect(
          fadeInStartX,
          fadeInTopY,
          fadeInEndX - fadeInStartX,
          fadeInHeight,
          CLIP_CORNER_RADIUS
        );
        ctx.clip();
        ctx.beginPath();
        ctx.roundRect(
          fadeInStartX + 0.5,
          fadeInTopY + 0.5,
          fadeInEndX - fadeInStartX - 1,
          fadeInHeight - 1,
          CLIP_CORNER_RADIUS
        );
        ctx.moveTo(fadeInEndX, fadeInTopY);
        ctx.bezierCurveTo(
          fadeInMiddleX,
          fadeInTopY,
          fadeInMiddleX,
          fadeInBottomY,
          fadeInStartX,
          fadeInBottomY
        );

        if (
          (hovered && !studioContext.inFlightDrags.isAnyDragging) ||
          studioContext.inFlightDrags.has(dragKey)
        )
          ctx.stroke();

        ctx.restore();

        ctx.fillStyle = 'rgba(255,255,255,0.15)';
        ctx.beginPath();
        ctx.roundRect(fadeInEndX, fadeInBottomY - 18, 10, 10, 2);
        ctx.closePath();
        ctx.fill();

        ctx.restore();
      },
    },
    {
      touchTarget: {
        bounds: {
          top: fadeInTopY,
          bottom: fadeInBottomY,
          left: fadeInEndX - EDGE_TOUCH_TARGET_WIDTH / 2,
          right: fadeInEndX + EDGE_TOUCH_TARGET_WIDTH / 2,
        },
        dragCursor: 'ew-resize',
        hoverCursor: 'ew-resize',
        hoverGroup: dragKey,
        onMouseDown: studioContext.handleClickDrag(({ downBeats }) => ({
          onMouseMove: ({ isDrag, moveBeats }) => {
            if (isDrag) {
              const rawDelta = moveBeats - downBeats;
              const effectiveDelta = Math.max(rawDelta, -1 * fadeDurationBeats);
              updateFadeInFlight(effectiveDelta);
            }
          },
          onMouseUp: ({ isDrag, upBeats }) => {
            if (isDrag) {
              const rawDelta = upBeats - downBeats;
              const effectiveDelta = Math.max(rawDelta, -1 * fadeDurationBeats);
              updateFadeState(effectiveDelta);
            }
          },
        })),
      },
      renderTop: (ctx: CanvasRenderingContext2D, hovered: boolean) => {
        if (
          !(
            (hovered && !studioContext.inFlightDrags.isAnyDragging) ||
            studioContext.inFlightDrags.has(dragKey)
          )
        )
          return;

        ctx.beginPath();
        ctx.roundRect(fadeInEndX - 3, fadeInTopY + 10, 6, fadeInHeight - 20, 3);
        ctx.fillStyle = '#ffffff';
        ctx.fill();
      },
    },
  ];
};

export const makeFadeOutRegions = (
  studioContext: StudioContextType,
  trackId: string,
  fadeOutEndBeats: number,
  fadeDurationBeats: number,
  updateFadeInFlight: (fadeDurationBeats: number) => void,
  updateFadeState: (fadeDurationBeats: number) => void,
  dragKey: string
): CanvasRegion[] => {
  const trackHeader =
    studioContext.timelineController.trackHeadersRef.current[trackId];
  if (!trackHeader) return [];

  const trackHeaderRect = getCanvasRelativeRect(
    trackHeader.getBoundingClientRect(),
    studioContext.timelineController.getWrapperRect()
  );

  const fadeOutStartBeats =
    fadeOutEndBeats -
    (fadeDurationBeats + studioContext.inFlightDrags.get(dragKey));
  const fadeOutEndX = studioContext.beatsToCanvasX(fadeOutEndBeats);
  const fadeOutStartX = studioContext.beatsToCanvasX(fadeOutStartBeats);
  const fadeOutTopY = trackHeaderRect.top;
  const fadeOutBottomY = trackHeaderRect.bottom;
  const fadeOutWidth = fadeOutEndX - fadeOutStartX;
  const fadeOutHeight = fadeOutBottomY - fadeOutTopY;
  const fadeOutMiddleX = (fadeOutStartX + fadeOutEndX) / 2;

  return [
    {
      touchTarget: {
        bounds: {
          top: fadeOutTopY,
          bottom: fadeOutBottomY,
          left: fadeOutStartX,
          right: fadeOutEndX,
        },
        passthrough: true,
        hoverGroup: dragKey,
      },
      renderTop: (ctx: CanvasRenderingContext2D, hovered: boolean) => {
        ctx.save();
        ctx.roundRect(
          fadeOutStartX,
          fadeOutTopY,
          fadeOutWidth,
          fadeOutHeight,
          CLIP_CORNER_RADIUS
        );
        ctx.clip();
        ctx.beginPath();
        ctx.strokeStyle = 'rgba(255,255,255,1.0)';
        ctx.fillStyle = 'rgba(0,0,0,0.2)';
        ctx.moveTo(fadeOutStartX, fadeOutTopY);
        ctx.lineTo(fadeOutEndX, fadeOutTopY);
        ctx.lineTo(fadeOutEndX, fadeOutBottomY);
        ctx.bezierCurveTo(
          fadeOutMiddleX,
          fadeOutBottomY,
          fadeOutMiddleX,
          fadeOutTopY,
          fadeOutStartX,
          fadeOutTopY
        );
        ctx.fill();

        ctx.save();
        ctx.beginPath();
        ctx.roundRect(
          fadeOutStartX,
          fadeOutTopY,
          fadeOutEndX - fadeOutStartX,
          fadeOutHeight,
          CLIP_CORNER_RADIUS
        );
        ctx.clip();
        ctx.beginPath();
        ctx.roundRect(
          fadeOutStartX + 0.5,
          fadeOutTopY + 0.5,
          fadeOutEndX - fadeOutStartX - 1,
          fadeOutHeight - 1,
          CLIP_CORNER_RADIUS
        );
        ctx.moveTo(fadeOutEndX, fadeOutBottomY);
        ctx.bezierCurveTo(
          fadeOutMiddleX,
          fadeOutBottomY,
          fadeOutMiddleX,
          fadeOutTopY,
          fadeOutStartX,
          fadeOutTopY
        );
        if (
          (hovered && !studioContext.inFlightDrags.isAnyDragging) ||
          studioContext.inFlightDrags.has(dragKey)
        )
          ctx.stroke();
        ctx.restore();

        ctx.fillStyle = 'rgba(255,255,255,0.15)';
        ctx.beginPath();
        ctx.roundRect(fadeOutEndX, fadeOutBottomY - 18, 10, 10, 2);
        ctx.closePath();
        ctx.fill();

        ctx.restore();
      },
    },
    {
      touchTarget: {
        bounds: {
          top: fadeOutTopY,
          bottom: fadeOutBottomY,
          left: fadeOutStartX - EDGE_TOUCH_TARGET_WIDTH / 2,
          right: fadeOutStartX + EDGE_TOUCH_TARGET_WIDTH / 2,
        },
        hoverCursor: 'ew-resize',
        dragCursor: 'ew-resize',
        hoverGroup: dragKey,
        onMouseDown: studioContext.handleClickDrag(({ downBeats }) => ({
          onMouseMove: ({ isDrag, moveBeats }) => {
            if (isDrag) {
              const rawDelta = moveBeats - downBeats;
              const effectiveDelta = Math.min(rawDelta, fadeDurationBeats);
              updateFadeInFlight(-effectiveDelta);
            }
          },
          onMouseUp: ({ isDrag, upBeats }) => {
            if (isDrag) {
              const rawDelta = upBeats - downBeats;
              const effectiveDelta = Math.min(rawDelta, fadeDurationBeats);
              updateFadeState(-effectiveDelta);
            }
          },
        })),
      },
      renderTop: (ctx: CanvasRenderingContext2D, hovered: boolean) => {
        if (
          !(
            (hovered && !studioContext.inFlightDrags.isAnyDragging) ||
            studioContext.inFlightDrags.has(dragKey)
          )
        )
          return;
        ctx.beginPath();
        ctx.roundRect(
          fadeOutStartX - 3,
          fadeOutTopY + 10,
          6,
          fadeOutHeight - 20,
          3
        );
        ctx.fillStyle = '#ffffff';
        ctx.fill();
      },
    },
  ];
};
