<template>
  <div class="px-4 h-full flex flex-col">
    <div class="rounded-md border flex-1 min-h-0 overflow-hidden">
      <!-- Locked: two-pane layout (fixed left pane + horizontally scrollable right pane) -->
      <template v-if="lockColumns">
        <div v-if="hasRows" class="flex h-full">
          <!-- Left pane: frozen columns (no horizontal scroll, vertical scroll hidden + synced) -->
          <div ref="leftPane" class="flex-shrink-0 h-full overflow-y-auto scrollbar-hide border-r" @scroll="onLeftScroll">
            <table class="caption-bottom text-sm">
              <TableHeader class="sticky top-0 z-10 bg-background">
                <TableRow v-for="headerGroup in table.getHeaderGroups()" :key="headerGroup.id">
                  <TableHead
                    v-for="header in frozenHeaders(headerGroup)"
                    :key="header.id"
                    :style="frozenWidth(header.column.id)"
                    :class="header.column.getCanSort() ? 'cursor-pointer select-none hover:bg-muted/50' : ''"
                    @click="header.column.getCanSort() ? header.column.toggleSorting() : null"
                  >
                    <FlexRender
                      v-if="!header.isPlaceholder"
                      :render="header.column.columnDef.header"
                      :props="header.getContext()"
                    />
                  </TableHead>
                </TableRow>
              </TableHeader>
              <TableBody>
                <TableRow
                  v-for="row in table.getRowModel().rows"
                  :key="row.id"
                  :data-state="row.getIsSelected() ? 'selected' : undefined"
                  class="cursor-pointer hover:bg-muted/50 h-12"
                  :class="{ 'bg-muted/30': row.getIsSelected(), 'table-row-selectable': true, 'selecting': isRangeSelecting }"
                  @click="handleRowClick(row.original, $event, row)"
                  @dblclick="emit('row-dblclick', row.original)"
                  @mousedown="handleMouseDown"
                  @mouseup="handleMouseUp"
                >
                  <TableCell
                    v-for="cell in frozenCells(row)"
                    :key="cell.id"
                    :style="frozenWidth(cell.column.id)"
                  >
                    <FlexRender :render="cell.column.columnDef.cell" :props="cell.getContext()" />
                  </TableCell>
                </TableRow>
              </TableBody>
            </table>
          </div>

          <!-- Right pane: movable columns (own horizontal scrollbar, only shown when needed) -->
          <div ref="rightPane" class="flex-1 min-w-0 h-full overflow-auto" @scroll="onRightScroll">
            <table class="min-w-full caption-bottom text-sm">
              <TableHeader class="sticky top-0 z-10 bg-background">
                <TableRow v-for="headerGroup in table.getHeaderGroups()" :key="headerGroup.id">
                  <TableHead
                    v-for="header in movableHeaders(headerGroup)"
                    :key="header.id"
                    :class="[
                      header.column.getCanSort() ? 'cursor-pointer select-none hover:bg-muted/50' : '',
                      header.column.id === 'actions' ? 'w-12' : '',
                      allTaskTypes.includes(header.column.id) ? 'w-[140px]' : '',
                    ]"
                    @click="header.column.getCanSort() ? header.column.toggleSorting() : null"
                  >
                    <FlexRender
                      v-if="!header.isPlaceholder"
                      :render="header.column.columnDef.header"
                      :props="header.getContext()"
                    />
                  </TableHead>
                </TableRow>
              </TableHeader>
              <TableBody>
                <TableRow
                  v-for="row in table.getRowModel().rows"
                  :key="row.id"
                  :data-state="row.getIsSelected() ? 'selected' : undefined"
                  class="cursor-pointer hover:bg-muted/50 h-12"
                  :class="{ 'bg-muted/30': row.getIsSelected(), 'table-row-selectable': true, 'selecting': isRangeSelecting }"
                  @click="handleRowClick(row.original, $event, row)"
                  @dblclick="emit('row-dblclick', row.original)"
                  @mousedown="handleMouseDown"
                  @mouseup="handleMouseUp"
                >
                  <TableCell
                    v-for="cell in movableCells(row)"
                    :key="cell.id"
                    v-memo="[cell.getValue(), cell.column.getIsVisible()]"
                  >
                    <FlexRender :render="cell.column.columnDef.cell" :props="cell.getContext()" />
                  </TableCell>
                </TableRow>
              </TableBody>
            </table>
          </div>
        </div>
        <div v-else class="h-24 flex items-center justify-center text-sm text-muted-foreground">
          No results.
        </div>
      </template>

      <!-- Unlocked: standard single table -->
      <Table v-else>
        <TableHeader class="sticky top-0 z-10 bg-background">
          <TableRow v-for="headerGroup in table.getHeaderGroups()" :key="headerGroup.id">
            <TableHead
              v-for="header in headerGroup.headers"
              :key="header.id"
              v-show="header.column.getIsVisible()"
              :class="[
                header.column.getCanSort() ? 'cursor-pointer select-none hover:bg-muted/50' : '',
                header.column.id === 'select' ? 'w-12' : '',
                header.column.id === 'actions' ? 'w-12' : '',
                allTaskTypes.includes(header.column.id) ? 'w-[140px]' : '',
              ]"
              @click="header.column.getCanSort() ? header.column.toggleSorting() : null"
            >
              <FlexRender
                v-if="!header.isPlaceholder"
                :render="header.column.columnDef.header"
                :props="header.getContext()"
              />
            </TableHead>
          </TableRow>
        </TableHeader>
        <TableBody>
          <template v-if="table.getRowModel().rows?.length">
            <TableRow
              v-for="row in table.getRowModel().rows"
              :key="row.id"
              :data-state="row.getIsSelected() ? 'selected' : undefined"
              class="cursor-pointer hover:bg-muted/50"
              :class="{
                'bg-muted/30': row.getIsSelected(),
                'table-row-selectable': true,
                'selecting': isRangeSelecting
              }"
              @click="handleRowClick(row.original, $event, row)"
              @dblclick="emit('row-dblclick', row.original)"
              @mousedown="handleMouseDown"
              @mouseup="handleMouseUp"
            >
              <TableCell
                v-for="cell in row.getAllCells()"
                :key="cell.id"
                v-show="cell.column.getIsVisible()"
                v-memo="[cell.getValue(), cell.column.getIsVisible()]"
              >
                <FlexRender
                  :render="cell.column.columnDef.cell"
                  :props="cell.getContext()"
                />
              </TableCell>
            </TableRow>
          </template>
          <template v-else>
            <TableRow>
              <TableCell :colspan="columns.length" class="h-24 text-center">
                No results.
              </TableCell>
            </TableRow>
          </template>
        </TableBody>
      </Table>
    </div>
  </div>
</template>

<script setup lang="ts">

import { ref, computed, watch } from 'vue'
import {
  FlexRender,
  getCoreRowModel,
  getSortedRowModel,
  useVueTable,
  type ColumnDef,
  type HeaderGroup,
  type Row,
  type SortingState,
  type VisibilityState,
} from '@tanstack/vue-table'
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from '@/components/ui/table'
import { type Shot } from '@/services/shot'

interface Props {
  columns: ColumnDef<Shot>[]
  data: Shot[]
  sorting: SortingState
  columnVisibility: VisibilityState
  allTaskTypes: string[]
  lockColumns?: boolean
}

const props = defineProps<Props>()

// Frozen (locked) columns and their fixed widths (px), in column order.
const FROZEN: Record<string, number> = {
  select: 48,
  thumbnail: 96,
  name: 200,
}

const isFrozen = (id: string) => id in FROZEN

const frozenWidth = (id: string) => {
  const w = FROZEN[id]
  return w ? { width: `${w}px`, minWidth: `${w}px` } : undefined
}

// Column partitioning for the two-pane (locked) layout. Movable headers/cells
// respect column visibility; frozen ones are always shown.
const frozenHeaders = (group: HeaderGroup<Shot>) =>
  group.headers.filter((h) => isFrozen(h.column.id) && h.column.getIsVisible())
const movableHeaders = (group: HeaderGroup<Shot>) =>
  group.headers.filter((h) => !isFrozen(h.column.id) && h.column.getIsVisible())
const frozenCells = (row: Row<Shot>) =>
  row.getVisibleCells().filter((c) => isFrozen(c.column.id))
const movableCells = (row: Row<Shot>) =>
  row.getVisibleCells().filter((c) => !isFrozen(c.column.id))

const hasRows = computed(() => table.getRowModel().rows.length > 0)

// Sync vertical scroll between the two panes (right pane owns the scrollbars).
const leftPane = ref<HTMLElement>()
const rightPane = ref<HTMLElement>()
let syncing = false
const syncScroll = (from?: HTMLElement, to?: HTMLElement) => {
  if (syncing || !from || !to) return
  syncing = true
  to.scrollTop = from.scrollTop
  requestAnimationFrame(() => { syncing = false })
}
const onRightScroll = () => syncScroll(rightPane.value, leftPane.value)
const onLeftScroll = () => syncScroll(leftPane.value, rightPane.value)

const emit = defineEmits<{
  'update:sorting': [sorting: SortingState]
  'update:columnVisibility': [visibility: VisibilityState]
  'update:rowSelection': [selection: Record<string, boolean>]
  'row-click': [shot: Shot, event: MouseEvent]
  'row-dblclick': [shot: Shot]
  'selection-cleared': []
}>()

// Track the last selected row index for range selection
const lastSelectedIndex = ref<number | null>(null)
const isRangeSelecting = ref(false)
const rowSelection = ref<Record<string, boolean>>({})

const table = useVueTable({
  get data() {
    return props.data
  },
  get columns() {
    return props.columns
  },
  getCoreRowModel: getCoreRowModel(),
  getSortedRowModel: getSortedRowModel(),
  enableRowSelection: true,
  enableMultiRowSelection: true,
  getRowId: (row) => String(row.id),
  onSortingChange: (updaterOrValue) => {
    const newSorting =
      typeof updaterOrValue === 'function'
        ? updaterOrValue(props.sorting)
        : updaterOrValue
    emit('update:sorting', newSorting)
  },
  onColumnVisibilityChange: (updaterOrValue) => {
    const newVisibility =
      typeof updaterOrValue === 'function'
        ? updaterOrValue(props.columnVisibility)
        : updaterOrValue
    emit('update:columnVisibility', newVisibility)
  },
  // Re-add the onRowSelectionChange callback but make it work with our custom logic
  onRowSelectionChange: (updaterOrValue) => {
    const newSelection =
      typeof updaterOrValue === 'function'
        ? updaterOrValue(rowSelection.value)
        : updaterOrValue
    rowSelection.value = newSelection
  },
  state: {
    get sorting() {
      return props.sorting
    },
    get columnVisibility() {
      return props.columnVisibility
    },
    get rowSelection() {
      return rowSelection.value
    },
  },
})

const handleRowClick = (shot: Shot, event: MouseEvent, row: any) => {
  // If double-click handler will handle it, skip selection logic
  if (event.detail === 2) {
    return
  }

  // Check if we clicked on an interactive element (simplified check)
  const target = event.target as HTMLElement
  if (target) {
    // Check if we clicked on a button, checkbox, or other interactive element
    const interactiveElement = target.closest('button, input, select, textarea, a[href], [role="button"], [role="menuitem"]')
    if (interactiveElement) {
      return
    }
  }

  // Handle selection based on modifier keys
  handleRowSelection(row, event)
  emit('row-click', shot, event)
}

const handleRowSelection = (row: any, event: MouseEvent) => {
  const currentIndex = row.index
  const allRows = table.getRowModel().rows
  const shotId = String(row.id)
  
  if (event.shiftKey && lastSelectedIndex.value !== null) {
    // Prevent text selection when shift-clicking
    event.preventDefault()
    
    // Range selection
    const startIndex = Math.min(lastSelectedIndex.value, currentIndex)
    const endIndex = Math.max(lastSelectedIndex.value, currentIndex)
    
    // Create new selection object
    const newSelection: Record<string, boolean> = {}
    
    // Select all rows in the range
    for (let i = startIndex; i <= endIndex; i++) {
      if (allRows[i]) {
        newSelection[allRows[i].id] = true
      }
    }
    
    rowSelection.value = newSelection
    lastSelectedIndex.value = currentIndex
  } else if (event.ctrlKey || event.metaKey) {
    // Ctrl/Cmd + Click: Toggle individual selection (additional selection)
    const newSelection: Record<string, boolean> = { ...rowSelection.value }
    
    if (newSelection[shotId]) {
      // Row is selected, deselect it
      delete newSelection[shotId]
    } else {
      // Row is not selected, select it
      newSelection[shotId] = true
    }
    
    rowSelection.value = newSelection
    lastSelectedIndex.value = currentIndex
  } else {
    // Default: Single selection (clear others and select this one)
    // This applies even if the row is already selected - it becomes the only selection
    rowSelection.value = { [shotId]: true }
    lastSelectedIndex.value = currentIndex
  }
}

const handleMouseDown = (event: MouseEvent) => {
  // Detect if this is a range selection operation
  if (event.shiftKey) {
    isRangeSelecting.value = true
    // Prevent text selection immediately
    event.preventDefault()
  }
}

const handleMouseUp = () => {
  // Reset range selecting state
  isRangeSelecting.value = false
}

// Watch rowSelection changes and emit selection-change events
watch(
  rowSelection,
  (newSelection) => {
    emit('update:rowSelection', newSelection)
  },
  { deep: true }
)
</script>

<style scoped>
/* Prevent text selection during range selection */
.table-row-selectable.selecting {
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}

/* Prevent text selection on shift key operations */
.table-row-selectable {
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  -khtml-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}

/* Allow text selection for specific elements that should be selectable */
.table-row-selectable input,
.table-row-selectable textarea,
.table-row-selectable [contenteditable] {
  -webkit-user-select: text;
  -moz-user-select: text;
  -ms-user-select: text;
  user-select: text;
}

/* Hide the left pane's vertical scrollbar (its scroll is synced from the right pane) */
.scrollbar-hide {
  scrollbar-width: none; /* Firefox */
  -ms-overflow-style: none; /* IE/Edge */
}
.scrollbar-hide::-webkit-scrollbar {
  display: none; /* Chrome/Safari */
}
</style>
