import { h, type VNode } from 'vue';
import { ArrowUpDown } from 'lucide-vue-next';
import { Button } from '@/components/ui/button';
import type { ColumnDef } from '@tanstack/vue-table';
import { ColumnConfig } from '@/types';
import { Checkbox } from '@/components/ui/checkbox'

export function generateColumns<T extends object>(config: ColumnConfig<T>[]): ColumnDef<T>[] {
  return config.map(({ key, label, formatter, hide_value, width, style, sticky }) => ({
    accessorKey: key as string,
    accessorFn: (row: T) => {
      if (hide_value) return String(hide_value(row));
      // if formatter is given, use it for filtering/search too
      if (formatter) {
        return String(formatter(row));
      }
      const value = (row as any)[key];
      if (value instanceof Date) {
        return value.toLocaleDateString();
      }
      if (typeof value === 'object' && value !== null) {
        // flatten object by JSON.stringify for search
        return JSON.stringify(value);
      }
      return value;
    },
    meta: { label, sticky },
    header: ({ column }) => {
      return h(Button, {
        variant: 'ghost',
        class: 'flex w-full h-auto items-center justify-between gap-2 my-0.5 text-left whitespace-normal overflow-hidden',
        onClick: () => column.toggleSorting(column.getIsSorted() === 'asc'),
      }, () => [h("span", { class: "flex-1 break-words" }, label), h(ArrowUpDown, { class: 'h-4 w-4 shrink-0' })]);
    },
    cell: ({ row }) => {
      const originalRow = row.original as T;
      const value = formatter ? formatter(originalRow) : row.getValue(key as string);

      // If formatter returned a VNode, render it directly
      if (value && typeof value === 'object' && 'component' in value) {
        return value as VNode;
      }

      // Otherwise render as string
      let display = '';
      if (value instanceof Date) {
        display = value.toLocaleDateString();
      } else if (value != null) {
        display = String(value);
      }

      return h('div', { class: style ?? 'text-left' }, display);
    },
    size: width ?? 200,
    minSize: 50,
    maxSize: 600,
  }));
}


export function withSelection<T>(columns: ColumnDef<T>[]): ColumnDef<T>[] {
  return [
    {
      id: 'select',
      header: ({ table }) =>
        h(Checkbox, {
          modelValue: table.getIsAllPageRowsSelected(),
          'onUpdate:modelValue': (value: boolean | "indeterminate") =>
            table.toggleAllPageRowsSelected(!!value),
          ariaLabel: 'Select all',
        }),
      cell: ({ row }) =>
        h(Checkbox, {
          modelValue: row.getIsSelected(),
          'onUpdate:modelValue': (value: boolean | "indeterminate") =>
            row.toggleSelected(!!value),
          ariaLabel: 'Select row',
        }),
      enableSorting: false,
      enableHiding: false,
      size: 35,
      minSize: 35,
      maxSize: 35,
    },
    ...columns,
  ]
}

export function withRowNumber<T>(columns: ColumnDef<T>[]): ColumnDef<T>[] {
  return [
    {
      id: 'no',
      header: () => 'No.',
      cell: ({ row }) => String(row.index + 1),
      enableSorting: false,
      enableHiding: false,
      size: 50,
      minSize: 50,
      maxSize: 50,
    },
    ...columns,
  ];
}