<script setup>
import { computed, h, reactive, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useToggle, useElementSize } from '@vueuse/core';
import { useVuelidate } from '@vuelidate/core';
import { required, minLength } from '@vuelidate/validators';
import { useMessageFormatter } from 'shared/composables/useMessageFormatter';
import { useMapGetter } from 'dashboard/composables/store';
import Input from 'dashboard/components-next/input/Input.vue';
import Button from 'dashboard/components-next/button/Button.vue';
import TextArea from 'dashboard/components-next/textarea/TextArea.vue';
import Editor from 'dashboard/components-next/Editor/Editor.vue';
import CardLayout from 'dashboard/components-next/CardLayout.vue';
import Checkbox from 'dashboard/components-next/checkbox/Checkbox.vue';
import Icon from 'dashboard/components-next/icon/Icon.vue';
import TagMultiSelectComboBox from 'dashboard/components-next/combobox/TagMultiSelectComboBox.vue';
import ScenariosAPI from 'dashboard/api/captain/scenarios';
import { useRoute } from 'vue-router';
import { useAlert } from 'dashboard/composables';

const props = defineProps({
  id: {
    type: [Number, String],
    required: true,
  },
  title: {
    type: String,
    required: true,
  },
  description: {
    type: String,
    required: true,
  },
  instruction: {
    type: String,
    required: true,
  },
  tools: {
    type: Array,
    default: () => [],
  },
  selectable: {
    type: Boolean,
    default: false,
  },
  isSelected: {
    type: Boolean,
    default: false,
  },
  triggerKeywords: {
    type: String,
    default: '',
  },
  enabled: {
    type: Boolean,
    default: true,
  },
});

const emit = defineEmits(['select', 'hover', 'delete', 'update', 'duplicate']);

const { t } = useI18n();
const { formatMessage } = useMessageFormatter();

const modelValue = computed({
  get: () => props.isSelected,
  set: () => emit('select', props.id),
});

const state = reactive({
  id: '',
  title: '',
  description: '',
  instruction: '',
  trigger_keywords: '',
  tools: [],
  enabled: true,
});

const instructionContentRef = ref();

const [isEditing, toggleEditing] = useToggle();
const [isInstructionExpanded, toggleInstructionExpanded] = useToggle();
const isSuggesting = ref(false);
const route = useRoute();

const { height: contentHeight } = useElementSize(instructionContentRef);
const needsOverlay = computed(() => contentHeight.value > 160);

const allTools = useMapGetter('captainTools/getRecords');

const toolOptions = computed(() => {
  const options = allTools.value.map(tool => ({
    label: tool.title,
    value: tool.id,
  }));
  return options;
});

const startEdit = () => {
  Object.assign(state, {
    id: props.id,
    title: props.title,
    description: props.description,
    instruction: props.instruction,
    trigger_keywords: props.triggerKeywords,
    tools: props.tools || [],
    enabled: props.enabled,
  });
  toggleEditing(true);
};

const rules = {
  title: { required, minLength: minLength(1) },
  description: { required },
  instruction: { required },
};

const v$ = useVuelidate(rules, state);

const titleError = computed(() =>
  v$.value.title.$error
    ? t('CAPTAIN.ASSISTANTS.SCENARIOS.ADD.NEW.FORM.TITLE.ERROR')
    : ''
);

const descriptionError = computed(() =>
  v$.value.description.$error
    ? t('CAPTAIN.ASSISTANTS.SCENARIOS.ADD.NEW.FORM.DESCRIPTION.ERROR')
    : ''
);

const onClickUpdate = () => {
  v$.value.$touch();
  if (v$.value.$invalid) return;
  emit('update', { ...state });
  toggleEditing(false);
};

const instructionError = computed(() =>
  v$.value.instruction.$error
    ? t('CAPTAIN.ASSISTANTS.SCENARIOS.ADD.NEW.FORM.INSTRUCTION.ERROR')
    : ''
);

const onDeleteOrArchive = () => {
  if (props.selectable) {
    emit('update', { id: props.id, enabled: false });
  } else {
    emit('delete', props.id);
  }
};

const LINK_INSTRUCTION_CLASS =
  '[&_a[href^="tool://"]]:text-n-iris-11 [&_a:not([href^="tool://"])]:text-n-slate-12 [&_a]:pointer-events-none [&_a]:cursor-default';

const renderInstruction = instruction => () =>
  h('p', {
    class: `text-sm text-n-slate-12 py-4 mb-0 prose prose-sm min-w-0 break-words max-w-none ${LINK_INSTRUCTION_CLASS}`,
    innerHTML: instruction,
  });

const emitDuplicate = () => {
  emit('duplicate', {
    id: props.id,
    title: props.title,
    description: props.description,
    instruction: props.instruction,
    tools: props.tools || [],
  });
};

const onSuggestTriggers = async () => {
  if (!state.instruction && !state.title) {
    // using generic error message for now, can be extracted to i18n
    useAlert(
      t(
        'CAPTAIN.ASSISTANTS.SCENARIOS.ADD.NEW.FORM.TRIGGER_KEYWORDS.SUGGEST_ERROR'
      )
    );
    return;
  }

  isSuggesting.value = true;
  try {
    const assistantId = route.params.assistantId;
    const response = await ScenariosAPI.suggestTriggers({
      assistantId,
      title: state.title,
      description: state.description,
      instruction: state.instruction,
    });

    if (response.data.keywords) {
      state.trigger_keywords = response.data.keywords;
      useAlert(
        t(
          'CAPTAIN.ASSISTANTS.SCENARIOS.ADD.NEW.FORM.TRIGGER_KEYWORDS.SUGGEST_SUCCESS'
        )
      );
    }
  } catch (error) {
    const errorMessage =
      error?.response?.data?.error || 'Failed to suggest keywords';
    useAlert(errorMessage);
  } finally {
    isSuggesting.value = false;
  }
};
</script>

<template>
  <!-- eslint-disable vue/no-bare-strings-in-template -->
  <CardLayout
    selectable
    class="relative [&>div]:!py-4"
    :class="{
      '[&>div]:ltr:!pr-4 [&>div]:rtl:!pl-4': !isEditing,
      '[&>div]:ltr:!pr-10 [&>div]:rtl:!pl-10': isEditing,
      'opacity-60 saturate-50': !enabled && !isEditing,
    }"
    layout="row"
    @mouseenter="emit('hover', true)"
    @mouseleave="emit('hover', false)"
  >
    <div
      v-show="selectable && !isEditing"
      class="absolute top-[1.125rem] ltr:left-3 rtl:right-3"
    >
      <Checkbox v-model="modelValue" />
    </div>

    <div v-if="!isEditing" class="flex flex-col w-full">
      <div class="flex items-start justify-between w-full gap-2">
        <div class="flex flex-col items-start">
          <span class="text-sm text-n-slate-12 font-medium">
            {{ title }}
            <span
              v-if="!enabled"
              class="text-n-slate-11 text-xs font-normal ml-2"
            >
              {{
                `(${t('CAPTAIN.ASSISTANTS.SCENARIOS.DISABLED') || 'Desativado'})`
              }}
            </span>
          </span>
          <span class="text-sm text-n-slate-11 mt-2">
            {{ description }}
          </span>
        </div>
        <div class="flex items-center gap-2">
          <!-- <Button label="Test" slate xs ghost class="!text-sm" />
          <span class="w-px h-4 bg-n-weak" /> -->
          <Button icon="i-lucide-copy" slate xs ghost @click="emitDuplicate" />
          <span class="w-px h-4 bg-n-weak" />
          <Button icon="i-lucide-pen" slate xs ghost @click="startEdit" />
          <span class="w-px h-4 bg-n-weak" />
          <Button
            :icon="selectable ? 'i-lucide-archive' : 'i-lucide-trash'"
            slate
            xs
            ghost
            :title="
              selectable
                ? t('CAPTAIN.ASSISTANTS.SCENARIOS.ARCHIVE')
                : t('CAPTAIN.ASSISTANTS.SCENARIOS.DELETE')
            "
            @click="onDeleteOrArchive"
          />
        </div>
      </div>

      <div
        class="relative overflow-hidden transition-all duration-300 ease-in-out group/expandable"
        :class="{ 'cursor-pointer': needsOverlay }"
        :style="{
          maxHeight: isInstructionExpanded ? `${contentHeight}px` : '10rem',
        }"
        @click="needsOverlay ? toggleInstructionExpanded() : null"
      >
        <div ref="instructionContentRef">
          <component
            :is="renderInstruction(formatMessage(instruction, false))"
          />
        </div>

        <div
          class="absolute bottom-0 w-full flex items-end justify-center text-xs text-n-slate-11 bg-gradient-to-t h-40 from-n-solid-2 via-n-solid-2 via-10% to-transparent transition-all duration-500 ease-in-out px-2 py-1 rounded pointer-events-none"
          :class="{
            'visible opacity-100': !isInstructionExpanded,
            'invisible opacity-0': isInstructionExpanded || !needsOverlay,
          }"
        >
          <Icon
            icon="i-lucide-chevron-down"
            class="text-n-slate-7 mb-4 size-4 group-hover/expandable:text-n-slate-11 transition-colors duration-200"
          />
        </div>
      </div>
      <span
        v-if="tools?.length"
        class="text-sm text-n-slate-11 font-medium mb-1"
      >
        {{ t('CAPTAIN.ASSISTANTS.SCENARIOS.ADD.SUGGESTED.TOOLS_USED') }}
        {{ tools?.map(tool => `@${tool}`).join(', ') }}
      </span>
    </div>
    <div v-else class="flex flex-col gap-4 w-full">
      <Input
        v-model="state.title"
        :label="t('CAPTAIN.ASSISTANTS.SCENARIOS.ADD.NEW.FORM.TITLE.LABEL')"
        :placeholder="
          t('CAPTAIN.ASSISTANTS.SCENARIOS.ADD.NEW.FORM.TITLE.PLACEHOLDER')
        "
        :message="titleError"
        :message-type="titleError ? 'error' : 'info'"
      />

      <TextArea
        v-model="state.description"
        :label="
          t('CAPTAIN.ASSISTANTS.SCENARIOS.ADD.NEW.FORM.DESCRIPTION.LABEL')
        "
        :placeholder="
          t('CAPTAIN.ASSISTANTS.SCENARIOS.ADD.NEW.FORM.DESCRIPTION.PLACEHOLDER')
        "
        :message="descriptionError"
        :message-type="descriptionError ? 'error' : 'info'"
        show-character-count
      />
      <Editor
        v-model="state.instruction"
        :label="
          t('CAPTAIN.ASSISTANTS.SCENARIOS.ADD.NEW.FORM.INSTRUCTION.LABEL')
        "
        :placeholder="
          t('CAPTAIN.ASSISTANTS.SCENARIOS.ADD.NEW.FORM.INSTRUCTION.PLACEHOLDER')
        "
        :message="instructionError"
        :message-type="instructionError ? 'error' : 'info'"
        :show-character-count="false"
        enable-captain-tools
      />
      <div class="flex flex-col gap-2">
        <div class="flex items-center justify-between">
          <label class="text-xs font-medium text-n-slate-11">
            {{
              t(
                'CAPTAIN.ASSISTANTS.SCENARIOS.ADD.NEW.FORM.TRIGGER_KEYWORDS.LABEL'
              )
            }}
          </label>
          <Button
            :label="
              t(
                'CAPTAIN.ASSISTANTS.SCENARIOS.ADD.NEW.FORM.TRIGGER_KEYWORDS.SUGGEST_BUTTON'
              )
            "
            icon="i-lucide-sparkles"
            xs
            ghost
            slate
            :is-loading="isSuggesting"
            @click="onSuggestTriggers"
          />
        </div>
        <TextArea
          v-model="state.trigger_keywords"
          :placeholder="
            t(
              'CAPTAIN.ASSISTANTS.SCENARIOS.ADD.NEW.FORM.TRIGGER_KEYWORDS.PLACEHOLDER'
            )
          "
          min-height="80px"
        />
      </div>

      <div class="flex flex-col gap-2">
        <label class="text-xs font-medium text-n-slate-11">
          {{ t('CAPTAIN.ASSISTANTS.SCENARIOS.ADD.NEW.FORM.TOOLS.LABEL') }}
        </label>
        <TagMultiSelectComboBox
          v-model="state.tools"
          :options="toolOptions"
          :placeholder="
            t('CAPTAIN.ASSISTANTS.SCENARIOS.ADD.NEW.FORM.TOOLS.PLACEHOLDER')
          "
        />
      </div>
      <div class="flex items-center gap-3">
        <Button
          faded
          slate
          sm
          :label="t('CAPTAIN.ASSISTANTS.SCENARIOS.UPDATE.CANCEL')"
          @click="toggleEditing(false)"
        />
        <Button
          sm
          :label="t('CAPTAIN.ASSISTANTS.SCENARIOS.UPDATE.UPDATE')"
          @click="onClickUpdate"
        />
      </div>
    </div>
  </CardLayout>
</template>
