import styled from '@emotion/styled';
import { getBeatsFromZero } from '@suno/studiokit/timeMapping';
import { useAnimationFrame } from 'framer-motion';
import { useCallback, useContext, useEffect, useRef } from 'react';

import { useStores } from '@/app/(root)/AppProviders';
import useClip from '@/hooks/useClip';
import { SectionIcon, WaveformIcon } from '@/icons';

import { Divider, Panel, VerticalPanelGroup } from '../panelSystem/PanelSystem';
import EditModeContext from './EditModeContext';
import EditPlaybackContext from './EditPlaybackContext';
import EditTimelineContext from './EditTimelineContext';
import EditToolbar from './EditToolbar';
import PreviewClipContext from './PreviewClipContext';
import SelectionContext, { getEditCategory } from './SelectionContext';
import StemsContext from './StemsContext';
import TimelineContainer from './TimelineContainer';
import CanvasRenderer from './canvasRenderer/CanvasRenderer';
import { constructEditCanvasRenderContext } from './canvasRenderer/EditCanvasRenderContext';
import ScrollCatcher from './canvasRenderer/ScrollCatcher';
import applyAutoScrollLimiting from './canvasRenderer/applyAutoScrollLimiting';
import makeBaseClickHandlerRegion from './canvasRenderer/makeBaseClickHandlerRegion';
import makeBeatGridRegion from './canvasRenderer/makeBeatGridRegion';
import makeMainClipWaveformRegions from './canvasRenderer/makeMainClipWaveformRegions';
import makePlayheadRegion from './canvasRenderer/makePlayheadRegion';
import makePreviewClipRegions from './canvasRenderer/makePreviewClipRegions';
import makeScrollbarRegion from './canvasRenderer/makeScrollbarRegion';
import makeSectionRegions from './canvasRenderer/makeSectionRegions';
import makeSelectedLyricsRegion from './canvasRenderer/makeSelectedLyricsRegion';
import makeSelectionRegions from './canvasRenderer/makeSelectionRegions';
import {
  CanvasRendererContainer,
  TrackHeader,
  TrackHeaders,
} from './components';
import AlignedLyricsContext from './lyrics/AlignedLyricsContext';
import EditTimingContext from './queryHooks/EditTimingContext';

const SingleTrackTimelineWrapper = styled.div`
  display: grid;
  grid-template-columns: 36px 1fr;
  min-height: 100%;
  overflow: auto;
`;

const TrackPanelDivider = styled.div`
  height: 1px;
  background-color: rgba(255, 255, 255, 0.1);
`;

export default function SingleTrackTimeline({
  clipId,
  fadeOut,
}: {
  clipId: string;
  fadeOut: boolean;
}) {
  const editTimelineContext = useContext(EditTimelineContext);
  const {
    frameCountRef,
    scrollXRef,
    pxPerBeatRef,
    zoomAboutSelectionOrCenter,
    resetZoom,
    handleScroll,
    handleZoom,
    wrapperRef,
  } = editTimelineContext;

  const { clip } = useClip(clipId);
  const previewClipContext = useContext(PreviewClipContext);
  const stemsContext = useContext(StemsContext);
  const { previewEdit, applyPreviewEdit, songEndSeconds } = previewClipContext;
  const { editMode } = useContext(EditModeContext);
  const alignedLyricsContext = useContext(AlignedLyricsContext);
  const { isFocused: alignedLyricsFocused, selectedLyricsTiming } =
    alignedLyricsContext;
  const timing = useContext(EditTimingContext);

  const playbackContext = useContext(EditPlaybackContext);
  const selectionContext = useContext(SelectionContext);
  const {
    selectionStartSeconds,
    selectionEndSeconds,
    setSelectionStartSeconds,
    setSelectionEndSeconds,
    setSelection,
  } = selectionContext;

  const sectionHeaderRef = useRef<HTMLDivElement>(null);
  const waveformHeaderRef = useRef<HTMLDivElement>(null);
  useAnimationFrame(
    useCallback(
      () => playbackContext.playing && frameCountRef.current++,
      [playbackContext.playing, frameCountRef]
    )
  );

  const receiveWrapperRef = useCallback(
    (el: HTMLDivElement | null) => {
      wrapperRef.current = el;
      if (el) {
        resetZoom();
      }
    },
    [resetZoom]
  );

  useEffect(() => {
    resetZoom();
  }, [resetZoom]);

  const { edit } = useStores();

  const getCanvasRegions = useCallback(() => {
    const wrapper = wrapperRef.current;
    const waveformHeader = waveformHeaderRef.current;
    const sectionHeader = sectionHeaderRef.current;

    if (!wrapper || !waveformHeader || !sectionHeader) {
      return [];
    }

    if (!songEndSeconds || !timing) {
      const timelineWrapperRect = wrapper.getBoundingClientRect();
      return [
        {
          render: (ctx: CanvasRenderingContext2D) => {
            ctx.textAlign = 'center';
            ctx.textBaseline = 'middle';
            ctx.font = '10px "Input Sans", monospace';
            ctx.fillStyle = '#FFFFFF';
            ctx.fillText(
              'Loading...'.toUpperCase(),
              timelineWrapperRect.width / 2,
              timelineWrapperRect.height / 2
            );
          },
        },
      ];
    }

    const timelineWrapperRect = wrapper.getBoundingClientRect();
    const songStartBeats = getBeatsFromZero(0, timing);
    const songEndBeats = getBeatsFromZero(songEndSeconds, timing);

    applyAutoScrollLimiting(
      scrollXRef,
      pxPerBeatRef,
      timelineWrapperRect,
      songStartBeats,
      songEndBeats,
      zoomAboutSelectionOrCenter
    );

    const canvasRenderContext = constructEditCanvasRenderContext({
      editTimelineContext,
      selectionContext,
      previewClipContext,
      stemsContext,
      alignedLyricsContext,
      playbackContext,
      timing,

      timelineWrapperRect,
      timelineWrapper: wrapper,
      waveformHeader,
      sectionHeader,
      clipId,
      editMode,
      editSessionId: edit.editSessionId,
      stemRows: [],
    });

    // rendering
    const previewClipRegions = makePreviewClipRegions(canvasRenderContext);

    return [
      makeBeatGridRegion(canvasRenderContext),
      makeBaseClickHandlerRegion(canvasRenderContext),
      ...makeSectionRegions(canvasRenderContext),
      ...previewClipRegions.background,
      ...makeMainClipWaveformRegions(canvasRenderContext),
      ...previewClipRegions.foreground,
      ...(previewEdit || getEditCategory(editMode) === 'no-selection'
        ? []
        : makeSelectionRegions(canvasRenderContext)),
      makePlayheadRegion(canvasRenderContext),
      ...(selectedLyricsTiming && alignedLyricsFocused
        ? [makeSelectedLyricsRegion(canvasRenderContext)]
        : []),
      makeScrollbarRegion(canvasRenderContext),
    ];
  }, [
    clip?.metadata?.duration,
    timing,
    clipId,
    frameCountRef,
    selectionStartSeconds,
    selectionEndSeconds,
    setSelectionStartSeconds,
    setSelectionEndSeconds,
    playbackContext,
    setSelection,
    editMode,
    alignedLyricsFocused,
    applyPreviewEdit,
    previewEdit,
    edit.editSessionId,
    selectedLyricsTiming,
  ]);

  const getCanvasRegionsRef = useRef(getCanvasRegions);
  useEffect(() => {
    getCanvasRegionsRef.current = getCanvasRegions;
  }, [getCanvasRegions]);
  const stableGetCanvasRegions = useCallback(() => {
    return getCanvasRegionsRef.current();
  }, []);

  useAnimationFrame(
    useCallback(
      () => playbackContext.playing && frameCountRef.current++,
      [frameCountRef, playbackContext.playing]
    )
  );

  useEffect(() => {
    frameCountRef.current++;
  }, [selectionStartSeconds]);

  return (
    <TimelineContainer clipId={clipId}>
      <EditToolbar clipId={clipId} fadeOut={fadeOut} />
      <SingleTrackTimelineWrapper>
        <TrackHeaders>
          <VerticalPanelGroup>
            <Panel size={{ unit: 'px', count: 30 }}></Panel>
            <Divider influence='neither'>
              <TrackPanelDivider />
            </Divider>
            <Panel size={{ unit: 'px', count: 30 }}>
              <TrackHeader ref={sectionHeaderRef}>
                <SectionIcon className='h-5 w-5' />
              </TrackHeader>
            </Panel>
            <Divider influence='neither'>
              <TrackPanelDivider />
            </Divider>
            <Panel size={{ unit: 'fr', count: 1 }}>
              <TrackHeader ref={waveformHeaderRef}>
                <WaveformIcon className='h-5 w-5' />
              </TrackHeader>
            </Panel>
            <Divider influence='neither'>
              <TrackPanelDivider />
            </Divider>
            <Panel size={{ unit: 'px', count: 30 }}>
              <TrackHeader>
                {/* <PlusIcon className='w-4 h-4' /> */}
              </TrackHeader>
            </Panel>
          </VerticalPanelGroup>
        </TrackHeaders>
        <CanvasRendererContainer ref={receiveWrapperRef} fadeOut={fadeOut}>
          <ScrollCatcher
            onScroll={handleScroll}
            onZoom={handleZoom}
            scrollXRef={scrollXRef}
            pxPerBeatRef={pxPerBeatRef}
            invertZoom={false} // TODO
            zoomOnResize
          >
            <CanvasRenderer
              getCanvasRegions={stableGetCanvasRegions}
              frameCountRef={frameCountRef}
            />
          </ScrollCatcher>
        </CanvasRendererContainer>
      </SingleTrackTimelineWrapper>
    </TimelineContainer>
  );
}
