import { useState, useMemo } from 'react';
import { useGetModelsQuery } from 'librechat-data-provider/react-query';
import { Spinner, useToastContext, SelectDropDown } from '@librechat/client';
import { useForm, FormProvider, Controller, useWatch } from 'react-hook-form';
import {
  Tools,
  Capabilities,
  actionDelimiter,
  ImageVisionTool,
  defaultAssistantFormValues,
} from 'librechat-data-provider';
import type { FunctionTool, TConfig } from 'librechat-data-provider';
import type { AssistantForm, AssistantPanelProps } from '~/common';
import {
  useCreateAssistantMutation,
  useUpdateAssistantMutation,
  useAvailableAgentToolsQuery,
} from '~/data-provider';
import { cn, cardStyle, defaultTextProps, removeFocusOutlines } from '~/utils';
import AssistantConversationStarters from './AssistantConversationStarters';
import AssistantToolsDialog from '~/components/Tools/AssistantToolsDialog';
import { useSelectAssistant, useLocalize } from '~/hooks';
import { useAssistantsMapContext } from '~/Providers';
import AppendDateCheckbox from './AppendDateCheckbox';
import CapabilitiesForm from './CapabilitiesForm';
import AssistantAvatar from './AssistantAvatar';
import AssistantSelect from './AssistantSelect';
import ContextButton from './ContextButton';
import AssistantTool from './AssistantTool';
import Knowledge from './Knowledge';
import { Panel } from '~/common';
import Action from './Action';

const labelClass = 'mb-2 text-token-text-primary block font-medium';
const inputClass = cn(
  defaultTextProps,
  'flex w-full px-3 py-2 dark:border-gray-800 dark:bg-gray-800 rounded-xl mb-2',
  removeFocusOutlines,
);

export default function AssistantPanel({
  // index = 0,
  setAction,
  endpoint,
  actions = [],
  setActivePanel,
  documentsMap,
  assistant_id: current_assistant_id,
  setCurrentAssistantId,
  assistantsConfig,
  version,
}: AssistantPanelProps & { assistantsConfig?: TConfig | null }) {
  const modelsQuery = useGetModelsQuery();
  const assistantMap = useAssistantsMapContext();

  const { data: allTools = [] } = useAvailableAgentToolsQuery();
  const { onSelect: onSelectAssistant } = useSelectAssistant(endpoint);
  const { showToast } = useToastContext();
  const localize = useLocalize();

  const methods = useForm<AssistantForm>({
    defaultValues: defaultAssistantFormValues,
  });

  const [showToolDialog, setShowToolDialog] = useState(false);

  const { control, handleSubmit, reset, setValue, getValues } = methods;
  const assistant = useWatch({ control, name: 'assistant' });
  const functions = useWatch({ control, name: 'functions' });
  const assistant_id = useWatch({ control, name: 'id' });

  const activeModel = useMemo(() => {
    return assistantMap?.[endpoint]?.[assistant_id]?.model;
  }, [assistantMap, endpoint, assistant_id]);

  const toolsEnabled = useMemo(
    () => assistantsConfig?.capabilities?.includes(Capabilities.tools),
    [assistantsConfig],
  );
  const actionsEnabled = useMemo(
    () => assistantsConfig?.capabilities?.includes(Capabilities.actions),
    [assistantsConfig],
  );
  const retrievalEnabled = useMemo(
    () => assistantsConfig?.capabilities?.includes(Capabilities.retrieval),
    [assistantsConfig],
  );
  const codeEnabled = useMemo(
    () => assistantsConfig?.capabilities?.includes(Capabilities.code_interpreter),
    [assistantsConfig],
  );

  /* Mutations */
  const update = useUpdateAssistantMutation({
    onSuccess: (data) => {
      showToast({
        message: `${localize('com_assistants_update_success')} ${
          data.name ?? localize('com_ui_assistant')
        }`,
      });
    },
    onError: (err) => {
      const error = err as Error;
      showToast({
        message: `${localize('com_assistants_update_error')}${
          error.message ? ` ${localize('com_ui_error')}: ${error.message}` : ''
        }`,
        status: 'error',
      });
    },
  });

  const create = useCreateAssistantMutation({
    onSuccess: (data) => {
      setCurrentAssistantId(data.id);
      showToast({
        message: `${localize('com_assistants_create_success')} ${
          data.name ?? localize('com_ui_assistant')
        }`,
      });
    },
    onError: (err) => {
      const error = err as Error;
      showToast({
        message: `${localize('com_assistants_create_error')}${
          error.message ? ` ${localize('com_ui_error')}: ${error.message}` : ''
        }`,
        status: 'error',
      });
    },
  });

  const files = useMemo(() => {
    if (typeof assistant === 'string') {
      return [];
    }
    return assistant.files;
  }, [assistant]);

  const onSubmit = (data: AssistantForm) => {
    const tools: Array<FunctionTool | string> = [...functions].map((functionName) => {
      if (!functionName.includes(actionDelimiter)) {
        return functionName;
      } else {
        const assistant = assistantMap?.[endpoint]?.[assistant_id];
        const tool = assistant?.tools?.find((tool) => tool.function?.name === functionName);
        if (assistant && tool) {
          return tool;
        }
      }

      return functionName;
    });

    if (data.code_interpreter) {
      tools.push({ type: Tools.code_interpreter });
    }
    if (data.retrieval) {
      tools.push({ type: version == 2 ? Tools.file_search : Tools.retrieval });
    }
    if (data.image_vision) {
      tools.push(ImageVisionTool);
    }

    const {
      name,
      description,
      instructions,
      conversation_starters: starters,
      model,
      append_current_datetime,
    } = data;

    if (assistant_id) {
      update.mutate({
        assistant_id,
        data: {
          name,
          description,
          instructions,
          conversation_starters: starters.filter((starter) => starter.trim() !== ''),
          model,
          tools,
          endpoint,
          append_current_datetime,
        },
      });
      return;
    }

    create.mutate({
      name,
      description,
      instructions,
      conversation_starters: starters.filter((starter) => starter.trim() !== ''),
      model,
      tools,
      endpoint,
      version,
      append_current_datetime,
    });
  };

  let submitContext: string | JSX.Element;

  if (create.isLoading || update.isLoading) {
    submitContext = <Spinner className="icon-md" />;
  } else if (assistant_id) {
    submitContext = localize('com_ui_save');
  } else {
    submitContext = localize('com_ui_create');
  }

  return (
    <FormProvider {...methods}>
      <form
        onSubmit={handleSubmit(onSubmit)}
        className="h-auto w-full flex-shrink-0 overflow-x-hidden"
      >
        <div className="flex w-full flex-wrap">
          <Controller
            name="assistant"
            control={control}
            render={({ field }) => (
              <AssistantSelect
                reset={reset}
                value={field.value}
                endpoint={endpoint}
                documentsMap={documentsMap}
                allTools={allTools}
                setCurrentAssistantId={setCurrentAssistantId}
                selectedAssistant={current_assistant_id ?? null}
                createMutation={create}
              />
            )}
          />
          {/* Select Button */}
          {assistant_id && (
            <button
              className="btn btn-primary focus:shadow-outline mx-2 mt-1 h-[40px] rounded bg-green-500 px-4 py-2 font-semibold text-white hover:bg-green-400 focus:border-green-500 focus:outline-none focus:ring-0"
              type="button"
              disabled={!assistant_id}
              onClick={(e) => {
                e.preventDefault();
                onSelectAssistant(assistant_id);
              }}
            >
              {localize('com_ui_select')}
            </button>
          )}
        </div>
        <div className="bg-surface-50 h-auto px-4 pb-8 pt-3 dark:bg-transparent">
          {/* Avatar & Name */}
          <div className="mb-4">
            <AssistantAvatar
              createMutation={create}
              assistant_id={assistant_id}
              metadata={assistant['metadata'] ?? null}
              endpoint={endpoint}
              version={version}
            />
            <label className={labelClass} htmlFor="name">
              {localize('com_ui_name')}
            </label>
            <Controller
              name="name"
              control={control}
              render={({ field }) => (
                <input
                  {...field}
                  value={field.value ?? ''}
                  {...{ max: 256 }}
                  className={inputClass}
                  id="name"
                  type="text"
                  placeholder={localize('com_assistants_name_placeholder')}
                />
              )}
            />
            <Controller
              name="id"
              control={control}
              render={({ field }) => (
                <p className="h-3 text-xs italic text-text-secondary">{field.value}</p>
              )}
            />
          </div>
          {/* Description */}
          <div className="mb-4">
            <label className={labelClass} htmlFor="description">
              {localize('com_ui_description')}
            </label>
            <Controller
              name="description"
              control={control}
              render={({ field }) => (
                <input
                  {...field}
                  value={field.value ?? ''}
                  {...{ max: 512 }}
                  className={inputClass}
                  id="description"
                  type="text"
                  placeholder={localize('com_assistants_description_placeholder')}
                />
              )}
            />
          </div>

          {/* Instructions */}
          <div className="mb-6">
            <label className={labelClass} htmlFor="instructions">
              {localize('com_ui_instructions')}
            </label>
            <Controller
              name="instructions"
              control={control}
              render={({ field }) => (
                <textarea
                  {...field}
                  value={field.value ?? ''}
                  {...{ max: 32768 }}
                  className={cn(inputClass, 'min-h-[100px] resize-y')}
                  id="instructions"
                  placeholder={localize('com_assistants_instructions_placeholder')}
                  rows={3}
                />
              )}
            />
          </div>

          {/* Append Today's Date */}
          <AppendDateCheckbox control={control} setValue={setValue} getValues={getValues} />

          {/* Conversation Starters */}
          <div className="relative mb-6">
            {/* the label of conversation starters is in the component */}
            <Controller
              name="conversation_starters"
              control={control}
              defaultValue={[]}
              render={({ field }) => (
                <AssistantConversationStarters
                  field={field}
                  inputClass={inputClass}
                  labelClass={labelClass}
                />
              )}
            />
          </div>
          {/* Model */}
          <div className="mb-6">
            <label className={labelClass} htmlFor="model">
              {localize('com_ui_model')}
            </label>
            <Controller
              name="model"
              control={control}
              rules={{ required: true, minLength: 1 }}
              render={({ field, fieldState: { error } }) => (
                <>
                  <SelectDropDown
                    emptyTitle={true}
                    value={field.value}
                    setValue={field.onChange}
                    availableValues={modelsQuery.data?.[endpoint] ?? []}
                    showAbove={false}
                    showLabel={false}
                    className={cn(
                      cardStyle,
                      'flex h-[40px] w-full flex-none items-center justify-center px-4 hover:cursor-pointer',
                    )}
                    containerClassName={cn('rounded-md', error ? 'border-red-500 border-2' : '')}
                  />
                  {error && (
                    <span className="text-sm text-red-500 transition duration-300 ease-in-out">
                      {localize('com_ui_field_required')}
                    </span>
                  )}
                </>
              )}
            />
          </div>
          {/* Knowledge */}
          {(codeEnabled === true || retrievalEnabled === true) && version == 1 && (
            <Knowledge assistant_id={assistant_id} files={files} endpoint={endpoint} />
          )}
          {/* Capabilities */}
          <CapabilitiesForm
            version={version}
            endpoint={endpoint}
            codeEnabled={codeEnabled}
            assistantsConfig={assistantsConfig}
            retrievalEnabled={retrievalEnabled}
          />
          {/* Tools */}
          <div className="mb-6">
            <label className={labelClass}>
              {`${toolsEnabled === true ? localize('com_ui_tools') : ''}
              ${toolsEnabled === true && actionsEnabled === true ? ' + ' : ''}
              ${actionsEnabled === true ? localize('com_assistants_actions') : ''}`}
            </label>
            <div className="space-y-2">
              {functions.map((func, i) => (
                <AssistantTool
                  key={`${func}-${i}-${assistant_id}`}
                  tool={func}
                  allTools={allTools}
                  assistant_id={assistant_id}
                />
              ))}
              {actions
                .filter((action) => action.assistant_id === assistant_id)
                .map((action, i) => {
                  return <Action key={i} action={action} onClick={() => setAction(action)} />;
                })}
              <div className="flex space-x-2">
                {toolsEnabled === true && (
                  <button
                    type="button"
                    onClick={() => setShowToolDialog(true)}
                    className="btn btn-neutral border-token-border-light relative h-8 w-full rounded-lg font-medium"
                  >
                    <div className="flex w-full items-center justify-center gap-2">
                      {localize('com_assistants_add_tools')}
                    </div>
                  </button>
                )}
                {actionsEnabled === true && (
                  <button
                    type="button"
                    disabled={!assistant_id}
                    onClick={() => {
                      if (!assistant_id) {
                        return showToast({
                          message: localize('com_assistants_actions_disabled'),
                          status: 'warning',
                        });
                      }
                      setActivePanel(Panel.actions);
                    }}
                    className="btn btn-neutral border-token-border-light relative h-8 w-full rounded-lg font-medium"
                  >
                    <div className="flex w-full items-center justify-center gap-2">
                      {localize('com_assistants_add_actions')}
                    </div>
                  </button>
                )}
              </div>
            </div>
          </div>
          <div className="flex items-center justify-end gap-2">
            {/* Context Button */}
            <ContextButton
              assistant_id={assistant_id}
              activeModel={activeModel}
              setCurrentAssistantId={setCurrentAssistantId}
              createMutation={create}
              endpoint={endpoint}
            />
            {/* Submit Button */}
            <button
              className="btn btn-primary focus:shadow-outline flex w-full items-center justify-center px-4 py-2 font-semibold text-white hover:bg-green-600 focus:border-green-500"
              type="submit"
            >
              {submitContext}
            </button>
          </div>
        </div>
        <AssistantToolsDialog
          endpoint={endpoint}
          isOpen={showToolDialog}
          setIsOpen={setShowToolDialog}
        />
      </form>
    </FormProvider>
  );
}
