import { ref, computed, type Ref, type ComputedRef } from 'vue'

export interface UseDataTableOptions {
  data: Ref<any[]>
}

export interface UseDataTableReturn {
  filter: Ref<string>
  hiddenColumns: Ref<Set<string>>
  selectedRows: Ref<Set<number>>
  copiedCell: Ref<string | null>
  copiedAll: Ref<boolean>
  filteredData: ComputedRef<any[]>
  visibleColumns: ComputedRef<string[]>
  allColumns: ComputedRef<string[]>
  allRowsSelected: ComputedRef<boolean>
  toggleColumn: (column: string) => void
  toggleRow: (idx: number) => void
  toggleAllRows: () => void
  copyCell: (value: any, cellId: string) => Promise<void>
  copyAll: () => Promise<void>
  reset: () => void
  formatValue: (value: any) => string
}

export function useDataTable(options: UseDataTableOptions): UseDataTableReturn {
  const { data } = options

  const filter = ref('')
  const hiddenColumns = ref<Set<string>>(new Set())
  const selectedRows = ref<Set<number>>(new Set())
  const copiedCell = ref<string | null>(null)
  const copiedAll = ref(false)

  const allColumns = computed(() => {
    if (data.value.length === 0) return []
    return Object.keys(data.value[0])
  })

  const visibleColumns = computed(() => {
    return allColumns.value.filter(col => !hiddenColumns.value.has(col))
  })

  const filteredData = computed(() => {
    if (!filter.value.trim()) return data.value
    const search = filter.value.toLowerCase()
    return data.value.filter(row =>
      Object.values(row).some(val =>
        String(val).toLowerCase().includes(search)
      )
    )
  })

  const allRowsSelected = computed(() => {
    if (filteredData.value.length === 0) return false
    return filteredData.value.every((_, idx) => selectedRows.value.has(idx))
  })

  function toggleColumn(column: string) {
    if (hiddenColumns.value.has(column)) {
      hiddenColumns.value.delete(column)
    } else {
      hiddenColumns.value.add(column)
    }
  }

  function toggleRow(idx: number) {
    if (selectedRows.value.has(idx)) {
      selectedRows.value.delete(idx)
    } else {
      selectedRows.value.add(idx)
    }
  }

  function toggleAllRows() {
    if (allRowsSelected.value) {
      selectedRows.value.clear()
    } else {
      filteredData.value.forEach((_, idx) => selectedRows.value.add(idx))
    }
  }

  function formatValue(value: any): string {
    if (value === null) return 'NULL'
    if (typeof value === 'object') return JSON.stringify(value)
    if (typeof value === 'string' && value.length > 100) {
      return value.substring(0, 100) + '...'
    }
    return String(value)
  }

  async function copyCell(value: any, cellId: string) {
    const textToCopy = value === null ? 'NULL' :
      typeof value === 'object' ? JSON.stringify(value, null, 2) : String(value)

    try {
      await navigator.clipboard.writeText(textToCopy)
      copiedCell.value = cellId
      setTimeout(() => {
        copiedCell.value = null
      }, 1500)
    } catch (e) {
      console.error('Failed to copy:', e)
    }
  }

  async function copyAll() {
    const rowsToUse = selectedRows.value.size > 0
      ? filteredData.value.filter((_, idx) => selectedRows.value.has(idx))
      : filteredData.value

    const dataToCopy = rowsToUse.map(row => {
      const filtered: Record<string, any> = {}
      visibleColumns.value.forEach(col => {
        filtered[col] = row[col]
      })
      return filtered
    })

    if (dataToCopy.length === 0) return

    try {
      const jsonText = JSON.stringify(dataToCopy, null, 2)
      await navigator.clipboard.writeText(jsonText)
      copiedAll.value = true
      setTimeout(() => {
        copiedAll.value = false
      }, 2000)
    } catch (e) {
      console.error('Failed to copy:', e)
    }
  }

  function reset() {
    filter.value = ''
    hiddenColumns.value.clear()
    selectedRows.value.clear()
  }

  return {
    filter,
    hiddenColumns,
    selectedRows,
    copiedCell,
    copiedAll,
    filteredData,
    visibleColumns,
    allColumns,
    allRowsSelected,
    toggleColumn,
    toggleRow,
    toggleAllRows,
    copyCell,
    copyAll,
    reset,
    formatValue
  }
}
