import { makeAutoObservable } from 'mobx';
import { DEFAULT_AUDIO_VOICE, useOpenAi } from '../../models/OpenAi';
import { useState } from 'react';
import { Button } from '../Button';
import { css } from 'glamor';
import { ClientOptions } from 'openai';
import { useLocalStyles } from '../../styles/defaults/useLocalStyles';
import { v4 as uuidv4 } from 'uuid';

interface TextToVoiceStylesType {
  container?: React.CSSProperties;
  button?: React.CSSProperties;
  audio?: React.CSSProperties;
}

/**
 * The props for the TextToVoice component
 */
interface TextToVoiceProps {
  /**
   * The id for the button of the component
   */
  id?: string;
  /**
   * The text to be converted to voice
   */
  text: string;
  /**
   * The voice to use for the conversion
   * @default 'alloy'
   */
  voice?: string;
  /**
   * The configuration for the openai client
   * @example { apiKey: 'my-api-key', organization: 'my-organization', dangerouslyAllowBrowser: true }
   */
  config: ClientOptions;
  /**
   * The style overwrites for the component
   */
  styleOverwrites?: TextToVoiceStylesType;
  /**
   * Whether to show the player or not
   * @default true
   */
  showPlayer?: boolean;
  /**
   * The children of the button component
   * @default 'generate audio'
   */
  children?: React.ReactNode;
}

/**
 * The state for the TextToVoice component
 */
class TextToVoiceState {
  /**
   * indicates the audio is processing, being created
   */
  loading: boolean;

  /**
   * The audio blob
   */
  audio?: Blob | null;
  constructor() {
    this.loading = false;
    this.audio = null;
    makeAutoObservable(this);
  }

  setLoading = (loading: boolean) => {
    this.loading = loading;
  };

  setAudio = (audio?: Blob) => {
    this.audio = audio;
  };
}

const TextToVoiceStyles: TextToVoiceStylesType = {
  container: {
    display: 'flex',
    flexDirection: 'row',
    columnGap: '10px',
    alignItems: 'center'
  },
  button: {},
  audio: {
    display: 'flex',
    flexDirection: 'row',
    columnGap: '10px',
    alignItems: 'center'
  }
};

/**
 * A component that converts text to voice.
 * This component uses the OpenAi library to convert text to voice.
 * @returns A react component
 */
export const TextToVoice = (props: TextToVoiceProps) => {
  const {
    id = uuidv4(),
    text,
    voice = DEFAULT_AUDIO_VOICE,
    showPlayer = true,
    config,
    styleOverwrites,
    children = 'generate audio'
  } = props;
  const state = new TextToVoiceState();
  const [audioUrl, setAudioUrl] = useState<string | null>(null);

  const { toAudio } = useOpenAi(config);
  const localStyles = useLocalStyles<TextToVoiceStylesType>(
    TextToVoiceStyles,
    styleOverwrites
  );

  return (
    <div {...css(localStyles.container)}>
      <Button
        gutters={undefined}
        id={`button-ai-text-to-voice-${id}`}
        loading={state.loading}
        styleOverwrites={localStyles.button}
        onClick={() => {
          state.setLoading(true);
          toAudio(text, voice).then((response) => {
            state.setAudio(response?.blob);
            if (response?.url) {
              setAudioUrl(response?.url);
            }

            state.setLoading(false);
          });
        }}
      >
        {children}
      </Button>
      {audioUrl && showPlayer && (
        <audio {...css(localStyles.audio)} controls>
          <source src={audioUrl} />
        </audio>
      )}
    </div>
  );
};
