<template>
  <template v-if="ToolOrReasoningParts.length > 0 || inProgress">
    <div 
      class="shine-text-container ml-2 px-4 flex items-center gap-1 select-none hover:opacity-80 tracking-wide font-medium text-sm text-listTableHeadingText dark:text-darkListTableHeadingText"
      :class="[ToolOrReasoningParts.length > 0 ? 'cursor-pointer' : '']"
      @click="isExpanded = !isExpanded"
    >
      <p 
        :class="[
          inProgress ? `
            shine-text text-listTableHeadingText dark:text-darkListTableHeadingText 
            bg-[linear-gradient(-65deg,currentColor,_rgb(120,120,120)_50%,currentColor)] 
            dark:bg-[linear-gradient(-65deg,currentColor,_rgb(250,250,250,0.8)_70%,currentColor)]
            ` 
          : '']"
      >
        {{ inProgress ? $t('Thinking') : $t('Thoughts') }} 
      </p>
      <ThreeDotsAnimation v-if="inProgress" />      
      <span v-if="thinkingDuration > 0">({{ (thinkingDuration/1000).toFixed(2) }} s)</span>
      <IconAngleDownOutline 
        v-if="ToolOrReasoningParts.length > 0"
        :class="isExpanded ? 'rotate-180' : 'rotate-0'"
        class="transition-transform duration-200"
      />
    </div>
    <transition name="expand" class="sm:max-h-96 max-h-48 overflow-y-auto mb-4 pt-1">
      <CustomAutoScrollContainer
        ref="scrollContainerRef"
        :enabled="isResponseInProgress"
        behavior="smooth"
        v-if="ToolOrReasoningParts.length > 0" 
        v-show="isExpanded"
        :threshold="5"
        :wrapperStyle="{
          marginRight: '1rem',
        }"
        :scrollBarAutoHide="false"
      >
        <ol class="ml-8 my-2 relative border-l border-l-2 border-black border-default border-listTableHeadingText dark:border-darkListTableHeadingText">
          <template v-for="(part, index) in ToolOrReasoningParts" :key="index">
            <ReasoningRenderer v-if="part.type === 'reasoning'" :state="part.state" :text="part.text" />
            <ToolsGroup v-else-if="part.type==='data-tool-call'" :toolGroup="groupToolCallParts(message, part)" :isExpanded="isExpanded" />
            <li v-else-if="part.type === 'data-rendering'" class="mb-6 mx-2 mt-2 px-2 z-50 overflow-hidden">
              <span class="bg-lightNavbar dark:bg-darkNavbar absolute flex items-center text-listTableHeadingText dark:text-darkListTableHeadingText justify-center w-5 h-5 rounded-full -start-[0.68rem] ring-4 ring-lightNavbar dark:ring-darkNavbar">
                <div class="w-2 h-2 rounded-full bg-current animate-pulse"></div>
              </span>
              <h3 class="flex items-center mb-1 text-sm ml-3 gap-1 text-listTableHeadingText dark:text-darkListTableHeadingText">
                <span class="font-semibold">{{ part.data?.label ?? 'Rendering...' }}</span>
                <ThreeDotsAnimation />
              </h3>
            </li>
          </template>
        </ol>
      </CustomAutoScrollContainer>
    </transition>
  </template>
</template>



<script setup lang="ts">
  import type { IFormattedToolCallPart, IMessage, IPart, IToolGroup } from '../types';
  import { ref, computed, watch, onUnmounted, onMounted, defineAsyncComponent } from 'vue';
  import ReasoningRenderer from './ReasoningRenderer.vue';
  import { IconAngleDownOutline } from '@iconify-prerendered/vue-flowbite';
  import ThreeDotsAnimation from './ThreeDotsAnimation.vue';
  import { useAgentStore } from '../composables/useAgentStore';
  import { getMessageParts } from '../utils';
  import ToolsGroup from './ToolsGroup.vue';

  const CustomAutoScrollContainer = defineAsyncComponent(() => import('../CustomAutoScrollContainer.vue'));

  const props = defineProps<{
    message: IMessage
    isLastMessageInChat: boolean
  }>()

  const agentStore = useAgentStore();
  const thinkingStartTime = ref<number | null>(null);
  const thinkingDuration = ref(0);
  const scrollContainerRef = ref<InstanceType<typeof CustomAutoScrollContainer> | null>(null);
  const innerScrollContainerRef = ref<HTMLElement | null>(null);
  const isExpanded = ref(true);
  let isUserScrolled = false;
  const ToolOrReasoningParts = computed(() => {
    return props.message.parts.filter((part: IPart) => {
      return part.type === 'data-tool-call'
        || part.type === 'reasoning'
        || isActiveRenderingPart(part);
    });
  });
  const isResponseInProgress = computed(() =>{
    return props.isLastMessageInChat && agentStore.isResponseInProgress; 
  });
  
  const showFakeThinkingMessage = computed(() => {
    if (props.message.parts.length === 0 && props.isLastMessageInChat) return true;
    return false;
  })

  const inProgress = computed(() => {
    return isResponseInProgress.value || showFakeThinkingMessage.value;
  })

  onMounted(() => {
    thinkingStartTime.value = Date.now();
    if (isResponseInProgress.value) {
      isExpanded.value = true;
    } else {
      isExpanded.value = false;
    }
  })

  onUnmounted(() => {
    scrollContainerRef.value?.container.scrollEl?.removeEventListener('scroll', handleScroll);
    scrollContainerRef.value?.container.scrollEl?.removeEventListener('wheel', toggleIsUserScrolled);
    scrollContainerRef.value?.container.scrollEl?.removeEventListener('touchmove', toggleIsUserScrolled);
  })

  watch(scrollContainerRef, async () => {
    if (innerScrollContainerRef.value) {
      innerScrollContainerRef.value.removeEventListener('scroll', handleScroll);
      innerScrollContainerRef.value.removeEventListener('wheel', toggleIsUserScrolled);
      innerScrollContainerRef.value.removeEventListener('touchmove', toggleIsUserScrolled);
    }

    if (scrollContainerRef.value) {
      innerScrollContainerRef.value = scrollContainerRef.value.container.scrollEl;
      innerScrollContainerRef.value.addEventListener('scroll', handleScroll);
      innerScrollContainerRef.value.addEventListener('wheel', toggleIsUserScrolled);
      innerScrollContainerRef.value.addEventListener('touchmove', toggleIsUserScrolled);

    }
  })

  watch(isResponseInProgress, (newValue: boolean) => {
    if (!newValue) {
      isExpanded.value = false;
      thinkingDuration.value = Date.now() - (thinkingStartTime.value ?? Date.now());
    }
  });

  const formatToolCallPart = (part: IPart, currentMessage: IMessage): IFormattedToolCallPart | null => {
    if (part.type !== 'data-tool-call' || part.data?.phase !== 'start') {
      return null;
    }

    const finishedPart = currentMessage.parts.find(candidate => {
      return candidate.type === 'data-tool-call'
        && candidate.data?.toolCallId === part.data?.toolCallId
        && candidate.data?.phase === 'end';
    });

    return {
      type: 'data-tool-call',
      toolInfo: {
        toolCallId: part.data.toolCallId,
        toolName: part.data.toolName,
        phase: finishedPart ? 'end' : 'start',
        durationMs: finishedPart?.data?.durationMs,
        input: part.data.input,
        output: finishedPart?.data?.output,
        toolInfo: part.data.toolInfo,
        error: finishedPart?.data?.error,
      }
    };
  };

  const getVisibleTimelineParts = (message: IMessage) => {
    return getMessageParts(message).filter(part => {
      return part.type === 'reasoning' || (part.type === 'data-tool-call' && part.data?.phase === 'start');
    });
  };

  function isActiveRenderingPart(part: IPart) {
    return part.type === 'data-rendering'
      && part.data?.phase === 'start'
      && !props.message.parts.some((candidate: IPart) => {
        return candidate.type === 'data-rendering' && candidate.data?.phase === 'end';
      });
  }

  const groupToolCallParts = (message: IMessage, currentPart: IPart): IToolGroup[] => {
    if (currentPart.type !== 'data-tool-call') {
      return [];
    }

    const visibleParts = getVisibleTimelineParts(message);
    const currentPartIndex = visibleParts.findIndex(part => part === currentPart);

    if (currentPartIndex === -1) {
      return [];
    }

    if (currentPartIndex > 0 && visibleParts[currentPartIndex - 1]?.type === 'data-tool-call') {
      return [];
    }

    const groupedParts: IToolGroup[] = [];

    for (let index = currentPartIndex; index < visibleParts.length; index += 1) {
      const part = visibleParts[index];

      if (part.type === 'reasoning') {
        break;
      }

      const formattedPart = formatToolCallPart(part, message);

      if (!formattedPart) {
        continue;
      }

      const lastGroup = groupedParts[groupedParts.length - 1];

      if (lastGroup?.title === formattedPart.toolInfo.toolName) {
        lastGroup.groupedTools.push(formattedPart);
        continue;
      }

      groupedParts.push({
        title: formattedPart.toolInfo.toolName,
        groupedTools: [formattedPart],
      });
    }

    return groupedParts;
  };

  function handleScroll() {
    if (isUserScrolled) { 
      scrollContainerRef.value?.handleScroll();
    }
  }

  function toggleIsUserScrolled() {
    isUserScrolled = true;
    setTimeout(() => {
      isUserScrolled = false;
    }, 100);
  }
</script>

<style scoped>
  .expand-enter-active,
  .expand-leave-active {
    transition: all 0.3s ease;
  }

  .expand-enter-from,
  .expand-leave-to {
    opacity: 0;
    max-height: 0;
  }

  .expand-enter-to,
  .expand-leave-from {
    opacity: 1;
    max-height: 384px;

    @media (max-width: 640px) {
      max-height: 192px;
    }
  }


.shine-text {

  background-clip: text;
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-position: -12rem;
}

.shine-text {
  animation: shineText 6s infinite linear;
}

@keyframes shineText {
  to {
    background-position: -100%;
  }
}

</style>
