<script setup lang="ts">
import {
  FlexRender,
  getCoreRowModel,
  getFilteredRowModel,
  getSortedRowModel,
  useVueTable,
  type ColumnDef,
  type ColumnFiltersState,
  type SortingState,
} from '@tanstack/vue-table'
import { computed, h, ref } from 'vue'
import type { MediaRecord } from '../types'
import { isUnseen } from '../utils/seen'
import CoverImage from './CoverImage.vue'
import NamePair from './NamePair.vue'
import ObjectTypeBadge from './ObjectTypeBadge.vue'
import DeleteButton from './DeleteButton.vue'

const props = defineProps<{
  data: MediaRecord[]
  deletingId?: number | null
  togglingSeenId?: number | null
}>()

const emit = defineEmits<{
  delete: [id: number]
  'toggle-seen': [record: MediaRecord]
}>()

function onRowClick(record: MediaRecord, event: MouseEvent) {
  const target = event.target as HTMLElement
  if (target.closest('button, a, input, select')) return
  emit('toggle-seen', record)
}

const defaultSorting: SortingState = [{ id: 'created_at', desc: true }]

const sorting = ref<SortingState>([...defaultSorting])
const columnFilters = ref<ColumnFiltersState>([])
const globalFilter = ref('')

const columns: ColumnDef<MediaRecord>[] = [
  {
    id: 'cover',
    header: 'Cover',
    accessorKey: 'cover_url',
    enableSorting: false,
    cell: ({ row }) =>
      h(CoverImage, {
        url: row.original.cover_url,
        id: row.original.id,
        hasCoverInDb: Boolean(row.original.cover_mime_type),
        size: 'table',
      }),
  },
  {
    id: 'object_type',
    header: 'Typ',
    accessorKey: 'object_type',
    enableSorting: false,
    cell: ({ row }) =>
      h(ObjectTypeBadge, {
        value: row.original.object_type,
      }),
  },
  {
    id: 'names',
    header: 'Dateinamen (Original → Neu)',
    accessorFn: (row) => `${row.file_name_original} ${row.file_name_new}`,
    cell: ({ row }) =>
      h(NamePair, {
        original: row.original.file_name_original,
        renamed: row.original.file_name_new,
      }),
    enableSorting: false,
  },
  {
    accessorKey: 'movie_rating',
    header: 'Rating',
    cell: (info) => {
      const v = info.getValue()
      if (!v) return '—'
      return h('span', { class: 'rating' }, String(v))
    },
  },
  { accessorKey: 'movie_votes', header: 'Votes' },
  { accessorKey: 'standard_video_format', header: 'Format' },
  { accessorKey: 'video_resolution', header: 'Auflösung' },
  { accessorKey: 'video_compression_format', header: 'Kompression' },
  { accessorKey: 'video_codec_library', header: 'Codec' },
  { accessorKey: 'audio_codec', header: 'Audio' },
  { accessorKey: 'audio_channel_layout', header: 'Kanäle' },
  { accessorKey: 'container_format', header: 'Container' },
  { accessorKey: 'overall_bitrate', header: 'Gesamt' },
  { accessorKey: 'video_bitrate', header: 'Video' },
  { accessorKey: 'audio_bitrate', header: 'Audio BR' },
  {
    accessorKey: 'created_at',
    header: 'Erstellt',
    sortingFn: (rowA, rowB) => {
      const ta = rowA.original.created_at
        ? new Date(rowA.original.created_at).getTime()
        : 0
      const tb = rowB.original.created_at
        ? new Date(rowB.original.created_at).getTime()
        : 0
      if (ta !== tb) return ta - tb
      return (rowA.original.id ?? 0) - (rowB.original.id ?? 0)
    },
    cell: (info) => {
      const v = info.getValue() as string | null
      if (!v) return '—'
      try {
        return new Date(v).toLocaleString('de-DE')
      } catch {
        return v
      }
    },
  },
  {
    id: 'actions',
    header: '',
    enableSorting: false,
    cell: ({ row }) =>
      h(
        'div',
        { onClick: (e: Event) => e.stopPropagation() },
        [
          h(DeleteButton, {
            loading: props.deletingId === row.original.id,
            onClick: () => emit('delete', row.original.id),
          }),
        ]
      ),
  },
]

function isFixedColumn(columnId: string): boolean {
  return columnId === 'cover' || columnId === 'names' || columnId === 'object_type'
}

function isShrinkColumn(columnId: string): boolean {
  return !isFixedColumn(columnId)
}

const table = useVueTable({
  get data() {
    return props.data
  },
  getRowId: (row) => String(row.id),
  columns,
  state: {
    get sorting() {
      return sorting.value
    },
    get columnFilters() {
      return columnFilters.value
    },
    get globalFilter() {
      return globalFilter.value
    },
  },
  onSortingChange: (updater) => {
    sorting.value = typeof updater === 'function' ? updater(sorting.value) : updater
  },
  onColumnFiltersChange: (updater) => {
    columnFilters.value =
      typeof updater === 'function' ? updater(columnFilters.value) : updater
  },
  onGlobalFilterChange: (updater) => {
    globalFilter.value =
      typeof updater === 'function' ? updater(globalFilter.value) : updater
  },
  getCoreRowModel: getCoreRowModel(),
  getSortedRowModel: getSortedRowModel(),
  getFilteredRowModel: getFilteredRowModel(),
  globalFilterFn: (row, _columnId, filterValue) => {
    const q = String(filterValue).toLowerCase()
    if (!q) return true
    const r = row.original
    const haystack = [
      r.file_name_original,
      r.file_name_new,
      r.standard_video_format,
      r.video_codec_library,
      r.audio_codec,
      r.container_format,
      r.object_type,
    ]
      .filter(Boolean)
      .join(' ')
      .toLowerCase()
    return haystack.includes(q)
  },
})

const displayRows = computed(() => table.getRowModel().rows)

defineExpose({ setGlobalFilter: (v: string) => { globalFilter.value = v } })
</script>

<template>
  <div class="table-wrap">
    <div class="table-toolbar">
      <input
        v-model="globalFilter"
        type="search"
        class="table-toolbar__search"
        placeholder="Schnellfilter in geladenen Daten…"
      />
      <span class="table-toolbar__count">{{ displayRows.length }} Zeilen</span>
    </div>

    <div class="table-scroll">
      <table class="media-table">
        <thead>
          <tr v-for="headerGroup in table.getHeaderGroups()" :key="headerGroup.id">
            <th
              v-for="header in headerGroup.headers"
              :key="header.id"
              :class="{
                sortable: header.column.getCanSort(),
                'th-cover': header.column.id === 'cover',
                'th-type': header.column.id === 'object_type',
                'th-names': header.column.id === 'names',
                'th-shrink': isShrinkColumn(header.column.id),
              }"
              @click="header.column.getToggleSortingHandler()?.($event)"
            >
              <FlexRender
                v-if="!header.isPlaceholder"
                :render="header.column.columnDef.header"
                :props="header.getContext()"
              />
              <span v-if="header.column.getIsSorted()" class="sort-icon">
                {{ header.column.getIsSorted() === 'asc' ? '↑' : '↓' }}
              </span>
            </th>
          </tr>
        </thead>
        <tbody>
          <tr
            v-for="row in displayRows"
            :key="row.original.id"
            class="row-clickable"
            :title="isUnseen(row.original) ? 'Tippen: als gesehen markieren' : 'Tippen: als ungesehen markieren'"
            :class="{
              'row-unseen': isUnseen(row.original),
              'row-busy': togglingSeenId === row.original.id,
            }"
            @click="onRowClick(row.original, $event)"
          >
            <td
              v-for="cell in row.getVisibleCells()"
              :key="cell.id"
              :class="{
                'td-cover': cell.column.id === 'cover',
                'td-type': cell.column.id === 'object_type',
                'td-names': cell.column.id === 'names',
                'td-actions': cell.column.id === 'actions',
                'td-shrink': !isFixedColumn(cell.column.id),
              }"
            >
              <FlexRender
                :render="cell.column.columnDef.cell"
                :props="cell.getContext()"
              />
            </td>
          </tr>
        </tbody>
      </table>
    </div>
  </div>
</template>

<style scoped>
.table-wrap {
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: var(--shadow);
}

.table-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem;
  padding: 0.85rem 1rem;
  border-bottom: 1px solid var(--border);
  background: var(--bg-card);
}

.table-toolbar__search {
  flex: 1;
  min-width: 200px;
}

.table-toolbar__count {
  font-size: 0.8rem;
  color: var(--text-muted);
  margin-left: auto;
}

.table-scroll {
  overflow: auto;
  max-height: calc(100vh - 248px);
  overflow-anchor: auto;
}

.media-table {
  width: max-content;
  min-width: 100%;
  table-layout: auto;
  border-collapse: collapse;
  font-size: 0.85rem;
}

thead {
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--bg-card);
}

th {
  text-align: left;
  padding: 0.65rem 0.5rem;
  font-weight: 600;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-muted);
  border-bottom: 1px solid var(--border-strong);
}

th.sortable {
  cursor: pointer;
  user-select: none;
}

th.sortable:hover {
  color: var(--text);
}

.sort-icon {
  margin-left: 0.25rem;
  color: var(--accent);
}

td {
  padding: 0.65rem 0.5rem;
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
}

/* Cover: feste Breite */
.th-cover,
.td-cover {
  width: 88px;
  padding-left: 0.5rem;
  padding-right: 0.35rem;
}

.th-type,
.td-type {
  width: 88px;
  text-align: center;
  vertical-align: middle;
}

/* Dateinamen: feste Breite (einzige „reservierte“ Spalte) */
.th-names,
.td-names {
  width: 360px;
  min-width: 280px;
  max-width: 420px;
  vertical-align: top;
}

/* Metadaten: automatische Breite nach Inhalt */
.th-shrink,
.td-shrink {
  white-space: nowrap;
  padding-left: 0.45rem;
  padding-right: 0.45rem;
}

.td-actions {
  text-align: center;
  vertical-align: middle;
}

tbody tr.row-clickable {
  cursor: pointer;
}

tbody tr:hover {
  background: var(--bg-hover);
}

tbody tr.row-unseen:hover {
  background: rgba(99, 102, 241, 0.22);
}

tbody tr.row-busy {
  opacity: 0.65;
  pointer-events: none;
}

.rating {
  font-weight: 700;
  color: var(--warning);
}
</style>
