import { observer } from 'mobx-react-lite';
import { useCallback, useRef } from 'react';

import { useStores } from '@/app/(root)/AppProviders';
import Button, { ButtonShape, ButtonVariant } from '@/components/button/Button';
import {
  AutoClipPlaybackProvider,
  useClipPlaybackContext,
} from '@/components/clipBrowser/useClipPlayback';
import HorizontalFader from '@/components/edit2025/HorizontalFader';
import { useContextSelector } from '@/hooks/useContextSelector';
import { EditUndoIcon } from '@/icons';
import { getClipTitle } from '@/utils/clip';

import CreateFormContext from '../../v2/CreateFormContext';
import { CreateModes } from '../../v2/types';
import { CreateV2Switch } from '../CreateV2Switch';
import CreateAudioDisplay from './CreateAudioDisplay';
import CreateCard from './CreateCard';
import { SongMeta } from './common';
import { useUrlAudioSampler } from './useUrlAudioSampler';

const SEMITONE_STEPS = [
  0.25, 0.2649, 0.2806, 0.2973, 0.315, 0.3337, 0.3536, 0.3746, 0.3969, 0.4204,
  0.4454, 0.4719, 0.5, 0.5297, 0.5612, 0.5946, 0.63, 0.6674, 0.7071, 0.7492,
  0.7937, 0.8409, 0.8909, 0.9439, 1.0, 1.0595, 1.1225, 1.1892, 1.2599, 1.3348,
  1.4142, 1.4983, 1.5874, 1.6818, 1.7818, 1.8877, 2.0, 2.1189, 2.2449, 2.3784,
  2.5198, 2.6697, 2.8284, 2.9966, 3.1748, 3.3636, 3.5636, 3.7755, 4.0,
];

const formatMultiplier = (value: number) => {
  return value.toFixed(2) + 'x';
};

const findClosestSemitoneStep = (value: number) => {
  return SEMITONE_STEPS.reduce((prev, curr) => {
    return Math.abs(curr - value) < Math.abs(prev - value) ? curr : prev;
  });
};

const PlayableClipSpeedCard = ({ clip }: { clip: any }) => {
  const { isPlaying, onPlayClick, getCurrentProgress, setCurrentProgress } =
    useClipPlaybackContext();
  const sampleAudio = useUrlAudioSampler(clip?.id, clip?.status);
  const frameCountRef = useRef<number>(0);

  const [speedMultiplier, setSpeedMultiplier] = useContextSelector(
    CreateFormContext,
    (context) =>
      context.selectState<number>([CreateModes.ADJUST_SPEED, 'speedMultiplier'])
  );

  const [keepPitch, setKeepPitch] = useContextSelector(
    CreateFormContext,
    (context) =>
      context.selectState<boolean>([CreateModes.ADJUST_SPEED, 'keepPitch'])
  );

  const minMultiplier = 0.25;
  const maxMultiplier = 4.0;

  const handleReset = useCallback(() => {
    setSpeedMultiplier(1);
    setKeepPitch(false);
  }, [setSpeedMultiplier, setKeepPitch]);

  const currentMultiplier = speedMultiplier || 1;
  const currentKeepPitch = keepPitch || false;

  const getPlaybackTime = useCallback(() => {
    return getCurrentProgress() * (clip.metadata?.duration ?? 0);
  }, [getCurrentProgress, clip.metadata?.duration]);

  const setPlaybackTime = useCallback(
    (time: number) => {
      const duration = clip.metadata?.duration ?? 0;
      setCurrentProgress(
        duration > 0 ? Math.max(0, Math.min(1, time / duration)) : 0
      );
    },
    [setCurrentProgress, clip.metadata?.duration]
  );

  return (
    <CreateCard
      title={
        <SongMeta
          title={getClipTitle(clip)}
          artworkUrl={clip.image_url ?? ''}
          duration={clip.metadata?.duration ?? 0}
          getPlaybackTime={getPlaybackTime}
          isPlaying={isPlaying}
          play={onPlayClick}
          pause={onPlayClick}
        />
      }
    >
      <div className='flex flex-col gap-4 p-4'>
        <CreateAudioDisplay
          isPlaying={isPlaying}
          sampleAudio={sampleAudio}
          getCurrentProgress={() =>
            getPlaybackTime() / (clip.metadata?.duration ?? 1)
          }
          setCurrentProgress={(progress) =>
            setPlaybackTime(progress * (clip.metadata?.duration ?? 0))
          }
          frameCountRef={frameCountRef}
        />

        {/* Speed Adjustment Section */}
        <div className='flex flex-col items-center justify-center gap-2 rounded-2xl bg-tertiary p-5'>
          <div className='rounded-full p-4 font-mono text-2xl font-medium text-foreground-primary'>
            {formatMultiplier(currentMultiplier)}
          </div>

          <div className='h-[40px] w-full'>
            <HorizontalFader
              value={
                currentMultiplier < 1
                  ? ((currentMultiplier - minMultiplier) /
                      (1 - minMultiplier)) *
                    0.5
                  : 0.5 + ((currentMultiplier - 1) / (maxMultiplier - 1)) * 0.5
              }
              anchorValue={0.5}
              onChange={(value) => {
                value = Math.max(0, Math.min(1, value));

                let newMultiplier;
                if (value < 0.5) {
                  newMultiplier =
                    minMultiplier + (value / 0.5) * (1 - minMultiplier);
                } else {
                  newMultiplier =
                    1 + ((value - 0.5) / 0.5) * (maxMultiplier - 1);
                }

                // If Keep Pitch is off, snap to semitone increments
                if (!currentKeepPitch) {
                  newMultiplier = findClosestSemitoneStep(newMultiplier);
                } else {
                  newMultiplier = Math.round(newMultiplier * 100) / 100;
                }

                newMultiplier = Math.max(
                  minMultiplier,
                  Math.min(maxMultiplier, newMultiplier)
                );

                setSpeedMultiplier(newMultiplier);
              }}
              onCommit={() => {}}
            />
          </div>

          <div className='flex w-full flex-row justify-between text-sm text-gray-400'>
            <span>{formatMultiplier(minMultiplier)}</span>
            <span>{formatMultiplier(maxMultiplier)}</span>
          </div>

          <div className='mt-4 flex w-full items-center justify-between'>
            <CreateV2Switch
              label='Keep Pitch'
              checked={currentKeepPitch}
              onChange={(checked: boolean) => setKeepPitch(checked)}
            />
            {currentMultiplier !== 1 && (
              <Button
                onClick={handleReset}
                variant={ButtonVariant.Glass}
                shape={ButtonShape.Pill}
                className='py-1.5 text-sm'
                aria-label='Reset speed to normal'
                icon={<EditUndoIcon className='h-4 w-4' />}
              >
                Reset
              </Button>
            )}
          </div>
        </div>
      </div>
    </CreateCard>
  );
};

export const ClipSpeedCard = observer(() => {
  const { clips } = useStores();

  const [clipId] = useContextSelector(CreateFormContext, (context) =>
    context.selectState<string>([CreateModes.ADJUST_SPEED, 'clipId'])
  );

  if (!clipId) {
    return null;
  }

  const clip = clips.clipById[clipId];

  if (!clip) {
    return null;
  }

  return (
    <AutoClipPlaybackProvider clip={clip} studioPreviewsWithContextWindow>
      <PlayableClipSpeedCard clip={clip} />
    </AutoClipPlaybackProvider>
  );
});

export default ClipSpeedCard;
