import styled from '@emotion/styled';
import { deleteIn } from 'lodash-redux-immutability';
import { observer } from 'mobx-react-lite';
import { useCallback, useRef } from 'react';

import Button, { ButtonShape, ButtonVariant } from '@/components/button/Button';
import { ClipContextProvider } from '@/components/clipBrowser/ClipContext';
import {
  AutoClipPlaybackProvider,
  useClipPlaybackContext,
} from '@/components/clipBrowser/useClipPlayback';
import useClip from '@/hooks/useClip';
import { useContextSelector } from '@/hooks/useContextSelector';
import { CloseIcon } from '@/icons';
import { Clip } from '@/state/clipStore';
import { getClipTitle } from '@/utils/clip';

import CreateFormContext from '../../v2/CreateFormContext';
import changeClipConditionType from '../../v2/actions/changeClipConditionType';
import {
  ClipConditionTypes,
  ConditionTypes,
  CoverCondition,
  TimedCondition,
  TimedConditionTypes,
} from '../../v2/types';
import { mapConditionTypeToAddConditionType } from '../../v2/utils/mapConditionType';
import { ClipConditionTypePicker } from './ClipConditionTypePicker';
import CreateAudioDisplay from './CreateAudioDisplay';
import CreateCard from './CreateCard';
import { SongMeta } from './common';
import { useUrlAudioSampler } from './useUrlAudioSampler';

const ContentWrapper = styled.div`
  padding: 0 16px 16px 16px;
`;

const getConditionDisplayName = (conditionType: ClipConditionTypes): string => {
  switch (conditionType) {
    case ConditionTypes.COVER:
      return 'cover';
    case ConditionTypes.UNDERPAINT:
      return 'underpaint';
    case ConditionTypes.OVERPAINT:
      return 'overpaint';
    case ConditionTypes.EXTEND:
      return 'extend';
    case ConditionTypes.INFILL:
      return 'infill';
    case ConditionTypes.SAMPLE:
      return 'sample';
    case ConditionTypes.REUSE_STYLES_LYRICS:
      return 'reuse styles lyrics';
    default:
      return conditionType;
  }
};

const ClipConditionCard = ({
  clipTitle,
  clipArtworkUrl,
  clipDurationSeconds,

  isPlaying,
  play,
  pause,
  getCurrentProgress,
  setCurrentProgress,

  sampleAudio,
  frameCountRef,

  onClear,
  conditionType,

  changeConditionType,
}: {
  clipTitle: string;
  clipArtworkUrl: string;
  clipDurationSeconds: number;

  isPlaying: boolean;
  play: () => void;
  pause: () => void;
  getCurrentProgress: () => number;
  setCurrentProgress: (progress: number) => void;

  sampleAudio: (progress: number) => number;
  frameCountRef?: React.RefObject<number>;

  onClear: () => void;
  conditionType: ClipConditionTypes;

  changeConditionType: (type: ClipConditionTypes) => void;
}) => {
  const getPlaybackTime = useCallback(() => {
    return getCurrentProgress() * clipDurationSeconds;
  }, [getCurrentProgress, clipDurationSeconds]);

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

  return (
    <CreateCard
      title={
        <SongMeta
          title={clipTitle}
          artworkUrl={clipArtworkUrl}
          duration={clipDurationSeconds}
          getPlaybackTime={getPlaybackTime}
          isPlaying={isPlaying}
          play={play}
          pause={pause}
        />
      }
      headerContent={
        <>
          <ClipConditionTypePicker
            conditionType={conditionType}
            changeConditionType={changeConditionType}
          />

          <Button
            shape={ButtonShape.Pill}
            icon={<CloseIcon />}
            aria-label={`Clear ${getConditionDisplayName(conditionType)} condition`}
            variant={ButtonVariant.Tertiary}
            onClick={onClear}
          />
        </>
      }
    >
      <ContentWrapper>
        <CreateAudioDisplay
          isPlaying={isPlaying}
          sampleAudio={sampleAudio}
          getCurrentProgress={() => getPlaybackTime() / clipDurationSeconds}
          setCurrentProgress={(progress) =>
            setPlaybackTime(progress * clipDurationSeconds)
          }
          frameCountRef={frameCountRef}
        />
      </ContentWrapper>
    </CreateCard>
  );
};

const PlayableCreateClipConditionCard = ({
  clip,
  conditionType,
  onClear,
}: {
  clip: Clip;
  conditionType: ClipConditionTypes;
  onClear: () => void;
}) => {
  const { isPlaying, onPlayClick, getCurrentProgress, setCurrentProgress } =
    useClipPlaybackContext();
  const sampleAudio = useUrlAudioSampler(clip?.id, clip?.status);
  const frameCountRef = useRef<number>(0);
  const setState = useContextSelector(
    CreateFormContext,
    (context) => context.setState
  );

  const addCondition = useContextSelector(
    CreateFormContext,
    (context) => context.addCondition
  );

  const changeConditionType = useCallback(
    (newType: ClipConditionTypes) => {
      const addConditionType = mapConditionTypeToAddConditionType(newType);

      if (addConditionType) {
        // Use unified addCondition with replacement
        addCondition(clip.id, addConditionType, conditionType);
      } else {
        // Fall back to old method for unsupported types
        setState(changeClipConditionType(conditionType, newType, clip));
      }
    },
    [setState, clip, conditionType, addCondition]
  );
  return (
    <ClipConditionCard
      clipTitle={getClipTitle(clip)}
      clipArtworkUrl={clip.image_url ?? ''}
      clipDurationSeconds={clip.metadata?.duration ?? 0}
      isPlaying={isPlaying}
      play={onPlayClick}
      pause={onPlayClick}
      getCurrentProgress={getCurrentProgress}
      setCurrentProgress={setCurrentProgress}
      sampleAudio={sampleAudio}
      frameCountRef={frameCountRef}
      onClear={onClear}
      conditionType={conditionType}
      changeConditionType={changeConditionType}
    />
  );
};

const CreateClipConditionCard = ({
  clip,
  conditionType,
  onClear,
}: {
  clip: Clip;
  conditionType: ClipConditionTypes;
  onClear: () => void;
}) => {
  return (
    <AutoClipPlaybackProvider clip={clip} studioPreviewsWithContextWindow>
      <ClipContextProvider clip={clip}>
        <PlayableCreateClipConditionCard
          clip={clip}
          conditionType={conditionType}
          onClear={onClear}
        />
      </ClipContextProvider>
    </AutoClipPlaybackProvider>
  );
};

export const CreateCoverCard = observer(() => {
  const coverCondition = useContextSelector(CreateFormContext, (context) => {
    const [coverCondition] = context.selectState<CoverCondition>([
      'global',
      'untimedConditions',
      ConditionTypes.COVER,
    ]);
    return coverCondition;
  });

  const setState = useContextSelector(
    CreateFormContext,
    (context) => context.setState
  );

  const { clip: coverClip } = useClip(coverCondition?.clipId);

  const clearCoverCondition = useCallback(() => {
    setState((state) => {
      const stateWithoutCover = deleteIn(state, [
        'global',
        'untimedConditions',
        ConditionTypes.COVER,
      ]);

      return stateWithoutCover;
    });
  }, [setState]);

  if (!coverCondition || !coverClip) {
    return null;
  }

  return (
    <CreateClipConditionCard
      clip={coverClip}
      conditionType={ConditionTypes.COVER}
      onClear={clearCoverCondition}
    />
  );
});

export const CreateTimedConditionCard = observer(() => {
  const [timedCondition, setTimedCondition] = useContextSelector(
    CreateFormContext,
    (context) => {
      return context.selectState<TimedCondition<TimedConditionTypes> | null>([
        'global',
        'timedCondition',
      ]);
    }
  );

  const setState = useContextSelector(
    CreateFormContext,
    (context) => context.setState
  );

  const { clip: timedClip } = useClip(timedCondition?.condition?.clipId);

  const isUnderpaintOrOverpaint =
    timedCondition?.type === ConditionTypes.UNDERPAINT ||
    timedCondition?.type === ConditionTypes.OVERPAINT;

  const clearTimedCondition = useCallback(() => {
    setTimedCondition(null);
  }, [setTimedCondition, setState]);

  if (!isUnderpaintOrOverpaint || !timedCondition || !timedClip) {
    return null;
  }

  return (
    <CreateClipConditionCard
      clip={timedClip}
      conditionType={timedCondition.type}
      onClear={clearTimedCondition}
    />
  );
});

export default ClipConditionCard;
