import { makeAutoObservable } from 'mobx';
import { OpenAi } from '../../models/OpenAi';

const openAi = new OpenAi(true);

export class SmartInputModel {
  /**
   * The value of the input for the AI Prompt Input
   */
  aiPrompt: string;
  /**
   * The context for the AI model, this is used to provide context
   * (or more information related to the prompt) to the AI model
   */
  context: string;
  /**
   * Whether the prompt is open or not
   * @default false
   */
  openPrompt: boolean;
  /**
   * The input ref for the input to be augmented
   */
  inputValueRef?: React.RefObject<HTMLInputElement> | null;
  /**
   * Whether the ai is currently being prompted or not
   */
  loading: boolean;
  /**
   * The onChange function for the input
   */
  onChange?: (value: string) => void;
  constructor() {
    this.aiPrompt = '';
    this.context = '';
    this.openPrompt = false;
    this.inputValueRef = null;
    this.loading = false;
    this.onChange = undefined;
    makeAutoObservable(this);
  }

  /**
   * Computed value derived from the input ref
   */
  get inputValue() {
    return this.inputValueRef?.current?.value;
  }

  /**
   * Set the ai prompt value
   * @param prompt the Ai Prompt
   */
  setAiPrompt = (prompt: string) => {
    this.aiPrompt = prompt;
  };

  /**
   * Sets the context for the AI model
   * @param context the context for the AI model
   */
  setContext = (context?: string) => {
    this.context = context || '';
  };

  /**
   * Set the prompt to be open or not
   * @param value boolean, whether the prompt is open or not
   */
  setOpenPrompt = (value: boolean) => {
    this.openPrompt = value;
  };

  /**
   * Toggles the prompt to be open or not
   */
  toggleOpenPrompt = () => {
    this.openPrompt = !this.openPrompt;
  };
  /**
   * Sets the loading value
   * @param value the loading value
   */
  setLoading = (value: boolean) => {
    this.loading = value;
  };

  /**
   * Sets the onChange function
   * @param onChange the onChange function
   */
  setOnChange = (onChange: (value: string) => void) => {
    this.onChange = onChange;
  };

  /**
   * @param ref the input ref
   */
  setInputRef = (ref: React.RefObject<HTMLInputElement> | null) => {
    this.inputValueRef = ref;
  };
  /**
   * Query the AI model
   */
  query = async () => {
    this.setLoading(true);
    const inputRef = this.inputValueRef;
    let context = this.context;

    if (this.inputValue !== '') {
      context = `${context} ${this.inputValue}`;
    }
    // query the AI model
    openAi.ask(this.aiPrompt, context).then((response) => {
      const message = response?.message;
      if (message) {
        this.setLoading(false);

        if (inputRef?.current) {
          inputRef.current.value = message;
          inputRef?.current?.focus();
          if (this.onChange) {
            this.onChange(message);
          }
        }
      }
    });
  };
}

const smartInputState = new SmartInputModel();
/**
 * Observable hook for the smart input. Note this is an observable hook.
 * It can be used outside of react components.
 * @returns the smart input state
 */
export const useSmartInput = () => {
  return smartInputState;
};
