import {
  Dispatch,
  SetStateAction,
  useCallback,
  useMemo,
  useState,
} from 'react';

import { VocalGenders } from '@/app/(root)/create/v2/types';
import { useContextSelector } from '@/hooks/useContextSelector';
import {
  DEFAULT_AUDIO_WEIGHT_VALUE,
  DEFAULT_CREATE_CONTROL_VALUE,
} from '@/utils/constants';

import {
  getInstrumentName,
  isNewTrackOrCurrentInstrumentName,
} from './ContextualBar/ContextualBarInstrumentPicker';
import StudioContext from './StudioContext';
import updateTrack from './actions/updateTrack';
import { getFocusedTrack } from './selectors';
import { DEFAULT_INSTRUMENT, InstrumentSpec } from './types';

export type BetaStemModel = 'a' | 'default';

export default function useContextualCreateFormState() {
  const styles = useContextSelector(
    StudioContext,
    (ctx) => ctx.stylesEditController.styles
  );
  const setStyles = useContextSelector(
    StudioContext,
    (ctx) => ctx.stylesEditController.setStyles
  );

  const excludeStyles = useContextSelector(
    StudioContext,
    (ctx) => ctx.stylesEditController.excludeStyles
  );
  const setExcludeStyles = useContextSelector(
    StudioContext,
    (ctx) => ctx.stylesEditController.setExcludeStyles
  );

  const lyrics = useContextSelector(
    StudioContext,
    (ctx) => ctx.lyricsEditController.editedLyrics || ''
  );
  const setLyrics = useContextSelector(
    StudioContext,
    (ctx) =>
      ctx.lyricsEditController.setEditedLyrics as Dispatch<
        SetStateAction<string>
      >
  );

  const [vocalGender, setVocalGender] = useState(VocalGenders.UNSPECIFIED);
  const [weirdness, setWeirdness] = useState(DEFAULT_CREATE_CONTROL_VALUE);
  const [styleInfluence, setStyleInfluence] = useState(
    DEFAULT_CREATE_CONTROL_VALUE
  );
  const [audioInfluence, setAudioInfluence] = useState(
    DEFAULT_AUDIO_WEIGHT_VALUE
  );
  const [mumbleMode, setMumbleMode] = useState(false);
  const [replaceMode, setReplaceMode] = useState<
    'smart_infill' | 'fixed_infill' | 'infill'
  >('smart_infill');

  const focusedTrack = useContextSelector(StudioContext, (ctx) =>
    getFocusedTrack(ctx.state)
  );
  const [newTrackInstrument, setNewTrackInstrument] =
    useState<InstrumentSpec>(DEFAULT_INSTRUMENT);

  const setState = useContextSelector(StudioContext, (ctx) => ctx.setState);

  const instrument = focusedTrack?.instrument || newTrackInstrument;

  const setInstrument = useCallback(
    (
      nextInstrument:
        | InstrumentSpec
        | ((prev: InstrumentSpec) => InstrumentSpec)
    ) => {
      if (typeof nextInstrument === 'function') {
        nextInstrument = nextInstrument(instrument);
      }
      if (!focusedTrack?.id) {
        setNewTrackInstrument(nextInstrument);
        return;
      }
      setState(
        updateTrack(focusedTrack.id, (track) => ({
          ...track,
          name: isNewTrackOrCurrentInstrumentName(track.name, track.instrument)
            ? getInstrumentName(nextInstrument)
            : track.name,
          instrument: nextInstrument,
        }))
      );
    },
    [setState, instrument, focusedTrack?.id]
  );

  const controlTags = useMemo(() => {
    return instrument.type === 'custom' ? (instrument.prompt ?? '') : '';
  }, [instrument]);

  const setControlTags = useCallback(
    (controlTags: string) => {
      setInstrument({
        type: 'custom',
        prompt: controlTags,
      });
    },
    [setInstrument]
  );

  return {
    styles,
    setStyles,

    excludeStyles,
    setExcludeStyles,

    lyrics,
    setLyrics,

    vocalGender,
    setVocalGender,

    weirdness,
    setWeirdness,

    styleInfluence,
    setStyleInfluence,

    audioInfluence,
    setAudioInfluence,

    mumbleMode,
    setMumbleMode,

    replaceMode,
    setReplaceMode,

    instrument,
    setInstrument,

    controlTags,
    setControlTags,
  };
}
