import styled from '@emotion/styled';
import {
  ComponentProps,
  useCallback,
  useContext,
  useMemo,
  useState,
} from 'react';

import useClickDrag from '@/hooks/useClickDrag';
import {
  ChevronDownIcon,
  ChevronUpIcon,
  CopyIcon,
  MoreHorizontalIcon,
  TrashIcon,
  VolumeOnIcon,
} from '@/icons';

import Button, { ButtonSize, ButtonVariant } from '../button/Button';
import {
  ContextMenuItem,
  ContextMenuTrigger,
} from '../contextMenu/ContextMenu';
import { Tooltip } from '../tooltip/Tooltip';
import EditPlaybackContext, {
  trackEffectivelyMuted,
} from './EditPlaybackContext';
import HorizontalFader from './HorizontalFader';
import StemsContext, {
  largeTrackHeight,
  mediumTrackHeight,
} from './StemsContext';
import { StyledTrackHeader } from './components';

const Wrapper = styled(StyledTrackHeader)<{ selected: boolean }>`
  display: flex;
  flex-direction: column;
  align-items: stretch;
  justify-content: flex-start;
  padding: 8px 10px;
  cursor: grab;
  &:active {
    cursor: grabbing;
  }
  text-transform: none;
  position: relative;
  ${({ selected }) =>
    selected
      ? `
      background-color: rgba(255, 255, 255, 0.05);
    `
      : ''}
  &:hover {
    background-color: rgba(255, 255, 255, 0.05);
  }
`;

const TrackDropzoneWrapper = styled.div`
  position: absolute;
  top: -2px;
  bottom: -2px;
  left: 0;
  right: 0;

  z-index: 2;
  display: none;
  grid-template-rows: 1fr 1fr;

  .dragging-track & {
    display: grid;
  }
`;

const BeforeDropper = styled.div`
  &:hover {
    border-top: 3px solid white;
  }
`;

const AfterDropper = styled.div`
  &:hover {
    border-bottom: 3px solid white;
  }
`;

const Header = styled.div`
  display: grid;
  grid-template-columns: 1fr 20px;
  gap: 2px;
  position: relative;
`;

const TrackNameContainer = styled.div`
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  text-transform: uppercase;
`;

const MenuButton = (props: ComponentProps<typeof Button>) => {
  return (
    <div className='relative h-full'>
      <Button
        className='absolute -inset-1'
        {...props}
        variant={ButtonVariant.Tertiary}
        icon={MoreHorizontalIcon}
        size={ButtonSize.Mini}
      />
    </div>
  );
};

export default function MultiTrackTrackHeader({
  trackId,
}: {
  trackId: string;
}) {
  const stemsContext = useContext(StemsContext);
  const playbackContext = useContext(EditPlaybackContext);
  const track = useMemo(
    () =>
      stemsContext.fullSongTrack.id === trackId
        ? stemsContext.fullSongTrack
        : stemsContext.stemTracks.find((t) => t.id === trackId),
    [stemsContext.stemTracks, trackId]
  );
  const toggleSelectedTrackId = useCallback(() => {
    stemsContext.setSelectedTrackId((prev) =>
      prev === trackId ? null : trackId
    );
  }, [stemsContext.setSelectedTrackId]);

  const commitAmplitude = useCallback(
    (value: number) => {
      if (track && !trackEffectivelyMuted(track, stemsContext.anyTrackSolo)) {
        playbackContext.setTrackAmplitude(trackId, value);
      }

      stemsContext.updateTrack(trackId, (prev) => ({
        ...prev,
        amplitude: value,
      }));
    },
    [playbackContext, stemsContext, trackId]
  );
  const commitBalance = useCallback(
    (value: number) => {
      playbackContext.setTrackBalance(trackId, value);
      stemsContext.updateTrack(trackId, (prev) => ({
        ...prev,
        balance: value,
      }));
    },
    [playbackContext, stemsContext, trackId]
  );
  const setMute = useCallback(
    (value: boolean) => {
      stemsContext.updateTrack(trackId, (prev) => ({
        ...prev,
        mute: value,
      }));
    },
    [stemsContext, trackId]
  );
  const toggleSolo = useCallback(
    (shiftClick: boolean) => {
      stemsContext.toggleTrackSolo(trackId, shiftClick);
    },
    [stemsContext, trackId]
  );
  const setTrackHeight = useCallback(
    (value: number) => {
      stemsContext.updateTrack(trackId, (prev) => ({
        ...prev,
        height: value,
      }));
    },
    [stemsContext, trackId]
  );
  const [isDragging, setIsDragging] = useState(false);
  const mouseDownRef = useClickDrag(
    useCallback(() => {
      if (trackId === stemsContext.fullSongTrack.id) return;

      setIsDragging(true);
      document.body.classList.add('dragging-track');
      return {
        onMouseUp: ({ event }) => {
          setIsDragging(false);
          document.body.classList.remove('dragging-track');
          const targetTrackHeader = (event.target as HTMLElement)?.closest(
            '[data-track]'
          ) as HTMLElement | undefined;
          if (!targetTrackHeader) return;

          const targetTrackId = targetTrackHeader.dataset?.['track'];
          const targetDropPosition = targetTrackHeader.dataset?.['position'];
          if (!targetTrackId) return;

          stemsContext.reorderTracks(
            trackId,
            targetTrackId,
            targetDropPosition === 'before'
          );
        },
      };
    }, [stemsContext, trackId])
  );

  if (!track) return;
  return (
    <Wrapper
      ref={mouseDownRef}
      onClick={toggleSelectedTrackId}
      selected={track.id === stemsContext.selectedTrackId}
    >
      {!isDragging && trackId !== stemsContext.fullSongTrack.id && (
        <TrackDropzoneWrapper>
          <BeforeDropper data-track={track.id} data-position='before' />
          <AfterDropper data-track={track.id} data-position='after' />
        </TrackDropzoneWrapper>
      )}
      <Header>
        <TrackNameContainer>{track.name}</TrackNameContainer>
        {track.stemType && (
          <ContextMenuTrigger
            placement='bottom-right'
            ButtonComponent={MenuButton}
            ContentsComponent={() => (
              <>
                <ContextMenuItem
                  icon={TrashIcon}
                  onClick={() => {
                    stemsContext.deleteStemTrack(trackId);
                  }}
                >
                  Delete Track
                </ContextMenuItem>
                <ContextMenuItem
                  icon={CopyIcon}
                  onClick={() => {
                    stemsContext.duplicateStemTrack(trackId);
                  }}
                >
                  Duplicate Track
                </ContextMenuItem>
              </>
            )}
          ></ContextMenuTrigger>
        )}
      </Header>
      <div className='mt-3 flex h-4 w-full items-center justify-stretch gap-2'>
        <Tooltip label={`Mute`}>
          <Button
            className='flex h-5 w-8 shrink-1 grow-0 items-center justify-center p-0 text-xs'
            variant={
              !track.mute ? ButtonVariant.Primary : ButtonVariant.Standard
            }
            icon={VolumeOnIcon}
            onClick={(e) => {
              e.stopPropagation();
              setMute(!track.mute);
            }}
          />
        </Tooltip>
        <div className='shrink-0 grow cursor-ew-resize'>
          <Tooltip label={`Volume`}>
            <div className='w-full'>
              <HorizontalFader
                dotSize={10}
                defaultValue={0.5}
                value={track.amplitude / 2}
                onChange={(value) =>
                  track &&
                  !trackEffectivelyMuted(track, stemsContext.anyTrackSolo) &&
                  playbackContext.setTrackAmplitude(trackId, value * 2)
                }
                onCommit={(value) => commitAmplitude(value * 2)}
              />
            </div>
          </Tooltip>
        </div>
        <Tooltip label={`Solo (Shift-Click to solo multiple tracks)`}>
          <Button
            className='flex h-5 w-8 shrink-1 grow-0 items-center justify-center p-0 text-xs'
            variant={
              track.solo ? ButtonVariant.Primary : ButtonVariant.Standard
            }
            icon={<span>S</span>}
            onClick={(e) => {
              e.stopPropagation();
              toggleSolo(e.shiftKey || e.metaKey || e.ctrlKey);
            }}
          />
        </Tooltip>
      </div>
      {track.height >= largeTrackHeight && (
        <div className='mt-5 h-4 w-full'>
          <Tooltip label={`Left-Right Balance`}>
            <div className='flex items-center justify-stretch gap-2'>
              <Button
                disabled
                className='flex h-5 w-8 shrink-1 grow-0 items-center justify-center p-0 text-xs'
                variant={ButtonVariant.Secondary}
                icon={<span>L</span>}
              />
              <div className='shrink-0 grow cursor-ew-resize'>
                <HorizontalFader
                  dotSize={10}
                  defaultValue={0.5}
                  anchorValue={0.5}
                  value={track.balance * 0.5 + 0.5}
                  onChange={(value) =>
                    playbackContext.setTrackBalance(trackId, 2 * (value - 0.5))
                  }
                  onCommit={(value) => commitBalance(2 * (value - 0.5))}
                />
              </div>
              <Button
                disabled
                className='flex h-5 w-8 shrink-1 grow-0 items-center justify-center p-0 text-xs'
                variant={ButtonVariant.Secondary}
                icon={<span>R</span>}
              />
            </div>
          </Tooltip>
        </div>
      )}
      <div className='grow' />
      <Button
        className='mt-2 h-4 w-full p-0'
        variant={ButtonVariant.Tertiary}
        icon={
          track.height >= largeTrackHeight ? ChevronUpIcon : ChevronDownIcon
        }
        onClick={(e) => {
          e.stopPropagation();
          setTrackHeight(
            track.height >= largeTrackHeight
              ? mediumTrackHeight
              : largeTrackHeight
          );
        }}
      />
    </Wrapper>
  );
}
