<script setup lang="ts">
import { watchDebounced } from '@vueuse/core'
import { computed, ref } from 'vue'
import { toast } from 'vue-sonner'

import TraceListSection from './TraceListSection.vue'
import TraceListTableHeader from './TraceListTableHeader.vue'
import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
} from '@/components/ui/alert-dialog'
import { Table, TableBody, TableCell, TableRow } from '@/components/ui/table'
import { useDeletePastedTrace } from '@/composables/useTraces'
import { useTracesStore } from '@/stores/tracesStore'
import { useUiStore } from '@/stores/uiStore'
import { WT1iser } from '@/services/wt1'
import type { TraceListSortDirection, TraceListSortField } from '@/types/trace-list'

const uiStore = useUiStore()
const tracesStore = useTracesStore()
const { mutateAsync: deletePastedTrace, isPending: isDeleting } = useDeletePastedTrace()

const showDeleteConfirm = ref(false)
const pastedSectionOpen = ref(true)
const datasetSectionOpen = ref(true)
const selectedPastedTraceId = ref<string | null>(null)
const sortField = ref<TraceListSortField | null>('start')
const sortDirection = ref<TraceListSortDirection>('desc')

const sortedFilteredTraces = computed(() => {
  const traces = [...uiStore.filteredTraces]
  if (!sortField.value) return traces

  const getComparableValue = (field: TraceListSortField, trace: (typeof traces)[number]) => {
    if (field === 'start') {
      return trace.begin ? new Date(trace.begin).getTime() : null
    }
    if (field === 'duration') {
      return trace.duration ?? null
    }
    return trace.tokens?.totalTokens ?? null
  }

  traces.sort((a, b) => {
    const aValue = getComparableValue(sortField.value as TraceListSortField, a)
    const bValue = getComparableValue(sortField.value as TraceListSortField, b)

    if (aValue === null && bValue === null) return 0
    if (aValue === null) return 1
    if (bValue === null) return -1

    const diff = aValue - bValue
    return sortDirection.value === 'asc' ? diff : -diff
  })

  return traces
})

const pastedTraces = computed(() =>
  sortedFilteredTraces.value.filter((trace) => trace.source === 'pasted'),
)

const datasetTraces = computed(() =>
  sortedFilteredTraces.value.filter((trace) => trace.source !== 'pasted'),
)

watchDebounced(
  () => [uiStore.nameSearchQuery, uiStore.resultSearchQuery],
  ([nameQuery, resultQuery]) => {
    if (nameQuery || resultQuery) {
      WT1iser.searchTraces(nameQuery ?? '', resultQuery ?? '')
    }
  },
  { debounce: 500 },
)

function askDeletePastedTrace(traceId: string) {
  selectedPastedTraceId.value = traceId
  showDeleteConfirm.value = true
}

function toggleSort(field: TraceListSortField) {
  if (sortField.value === field) {
    sortDirection.value = sortDirection.value === 'asc' ? 'desc' : 'asc'
    return
  }

  sortField.value = field
  sortDirection.value = 'desc'
}

async function confirmDeletePastedTrace() {
  if (!selectedPastedTraceId.value) return

  try {
    await deletePastedTrace(selectedPastedTraceId.value)

    if (uiStore.selectedTraceId === selectedPastedTraceId.value) {
      uiStore.selectTrace(undefined)
    }

    showDeleteConfirm.value = false
    selectedPastedTraceId.value = null
  } catch (error) {
    const message = error instanceof Error ? error.message : 'An unexpected error occurred'
    toast.error('Failed to delete pasted trace', {
      description: message,
    })
  }
}
</script>

<template>
  <div class="h-full w-full flex flex-col p-2">
    <div class="border rounded-lg">
      <Table>
        <TraceListTableHeader
          :has-api-traces="tracesStore.hasApiTraces"
          :name-search-query="uiStore.nameSearchQuery"
          :result-search-query="uiStore.resultSearchQuery"
          :sort-field="sortField"
          :sort-direction="sortDirection"
          @update:name-search-query="uiStore.nameSearchQuery = $event"
          @update:result-search-query="uiStore.resultSearchQuery = $event"
          @toggle-sort="toggleSort"
        />

        <TableBody class="text-base">
          <TraceListSection
            title="Pasted traces"
            :traces="pastedTraces"
            :is-open="pastedSectionOpen"
            empty-message="No pasted trace matching the filters."
            :show-delete-action="true"
            @toggle="pastedSectionOpen = !pastedSectionOpen"
            @request-delete="askDeletePastedTrace"
          />

          <TraceListSection
            title="Dataset traces"
            :traces="datasetTraces"
            :is-open="datasetSectionOpen"
            empty-message="No dataset trace matching the filters."
            @toggle="datasetSectionOpen = !datasetSectionOpen"
          />

          <TableRow
            v-if="uiStore.filteredTraces.length === 0 && tracesStore.traces?.data.length === 0"
          >
            <TableCell colspan="6" class="h-24 text-center text-muted-foreground">
              Paste a new trace or select a dataset in the settings.
            </TableCell>
          </TableRow>
        </TableBody>
      </Table>
    </div>

    <AlertDialog v-model:open="showDeleteConfirm">
      <AlertDialogContent class="p-4">
        <AlertDialogHeader>
          <AlertDialogTitle>Delete pasted trace?</AlertDialogTitle>
          <AlertDialogDescription>
            This will remove the trace. This action cannot be undone.
          </AlertDialogDescription>
        </AlertDialogHeader>
        <AlertDialogFooter>
          <AlertDialogCancel>Cancel</AlertDialogCancel>
          <AlertDialogAction
            class="bg-destructive hover:bg-destructive/90"
            :disabled="isDeleting"
            @click="confirmDeletePastedTrace"
          >
            {{ isDeleting ? 'Deleting...' : 'Delete' }}
          </AlertDialogAction>
        </AlertDialogFooter>
      </AlertDialogContent>
    </AlertDialog>
  </div>
</template>
