<template>
  <div class="crud-datatable">
    <Card>
      <template #content>
        <!-- Header mit Buttons -->
        <div class="flex justify-between items-center mb-4">
          <div class="font-semibold text-xl">{{ title }}</div>
          <div class="flex gap-2">
            <Button 
              v-if="showExportButton"
              label="Exportieren" 
              icon="pi pi-download" 
              outlined
              @click="exportMenu.toggle($event)"
              ref="exportButton"
            />
            <Menu ref="exportMenu" :model="exportItems" :popup="true" />
            <Button 
              v-if="enableColumnConfig"
              label="Spalten anpassen" 
              icon="pi pi-cog" 
              outlined
              @click="columnConfigDialog = true" 
            />
            <slot name="header-actions">
              <Button 
                v-if="showCreateButton"
                :label="createLabel" 
                icon="pi pi-plus" 
                @click="$emit('create')" 
              />
            </slot>
          </div>
        </div>

        <!-- Optional: Custom Filter Buttons -->
        <slot name="filter-buttons" :load-data="loadData"></slot>

        <!-- Filter Active Indicator -->
        <div v-if="hasActiveFilters" class="mb-3 p-3 bg-primary-50 dark:bg-primary-900/20 border border-primary-200 dark:border-primary-800 rounded-lg flex items-center justify-between">
          <div class="flex items-center gap-2">
            <i class="pi pi-filter text-primary-600 dark:text-primary-400"></i>
            <span class="text-sm text-primary-900 dark:text-primary-100">
              <strong>{{ filterCount }}</strong> {{ filterCount === 1 ? 'Filter aktiv' : 'Filter aktiv' }}
              <span v-if="filteredData.length > 0" class="text-primary-700 dark:text-primary-300">
                - {{ filteredData.length }} von {{ data.length }} {{ data.length === 1 ? 'Datensatz' : 'Datensätze' }} angezeigt
              </span>
            </span>
          </div>
          <Button 
            label="Filter zurücksetzen" 
            icon="pi pi-filter-slash" 
            text
            size="small"
            severity="secondary"
            @click="clearAllFilters"
          />
        </div>

        <!-- DataTable -->
        <DataTable
          ref="dt"
          v-model:filters="internalFilters"
          :value="data"
          :loading="loading"
          v-bind="mergedTableProps"
          filterDisplay="menu"
          @filter="onFilter"
        >
          <!-- Header mit Globaler Suche -->
          <template #header>
            <div class="flex justify-between flex-wrap gap-2">
              <slot name="filter-row"></slot>
              <IconField>
                <InputIcon><i class="pi pi-search" /></InputIcon>
                <InputText
                  v-model="internalFilters['global'].value"
                  placeholder="Suchen..."
                />
              </IconField>
            </div>
          </template>

          <!-- Dynamische Spalten basierend auf Config -->
          <template v-for="(column, index) in visibleColumnsOrdered" :key="column.key">
            <Column
              :field="column.field || column.key"
              :header="column.label"
              :sortable="column.sortable !== false"
              :style="column.style"
              :dataType="column.dataType"
              :showFilterMatchModes="column.showFilterMatchModes !== false"
              :showFilterOperator="column.showFilterOperator !== false"
              :frozen="freezeFirstColumn && index === 0"
              :alignFrozen="freezeFirstColumn && index === 0 ? 'left' : undefined"
            >
              <!-- Custom Body Template (via Slot) -->
              <template v-if="$slots[`body-${column.key}`]" #body="slotProps">
                <slot :name="`body-${column.key}`" v-bind="slotProps" />
              </template>

              <!-- Default Body Template -->
              <template v-else #body="{ data }">
                {{ getNestedValue(data, column.field || column.key) }}
              </template>

              <!-- Custom Filter Template -->
              <template v-if="column.filterable !== false" #filter="{ filterModel }">
                <slot :name="`filter-${column.key}`" :filterModel="filterModel">
                  <InputText 
                    v-model="filterModel.value" 
                    type="text" 
                    :placeholder="'Suche nach ' + column.label"
                  />
                </slot>
              </template>
            </Column>
          </template>

          <!-- Actions Column (immer sichtbar) -->
          <Column :exportable="false" style="min-width: 120px" header="Aktionen">
            <template #body="slotProps">
              <slot name="actions" v-bind="slotProps">
                <div class="flex gap-2">
                  <Button
                    v-if="showViewButton"
                    icon="pi pi-eye"
                    outlined
                    rounded
                    @click="$emit('view', slotProps.data)"
                    size="small"
                    severity="secondary"
                  />
                  <Button
                    v-if="showEditButton"
                    icon="pi pi-pencil"
                    outlined
                    rounded
                    @click="$emit('edit', slotProps.data)"
                    size="small"
                  />
                  <Button
                    v-if="showDeleteButton"
                    icon="pi pi-trash"
                    outlined
                    rounded
                    severity="danger"
                    @click="$emit('delete', slotProps.data)"
                    size="small"
                  />
                </div>
              </slot>
            </template>
          </Column>

          <template #empty>{{ emptyMessage }}</template>
          <template #loading>Lädt Daten. Bitte warten...</template>
        </DataTable>
      </template>
    </Card>

    <!-- Column Config Dialog (wiederverwendbar) -->
    <ColumnConfigDialog
      v-model:visible="columnConfigDialog"
      v-model:columns="availableColumns"
      v-model:visible-columns="visibleColumns"
      v-model:freeze-first-column="freezeFirstColumn"
      @save="saveColumnConfig"
    />
  </div>
</template>

<script setup>
import { ref, computed, onMounted, watch } from 'vue'
import { useToast } from 'primevue/usetoast'
import { FilterMatchMode, FilterOperator } from '@primevue/core/api'
import DataTable from 'primevue/datatable'
import Column from 'primevue/column'
import Button from 'primevue/button'
import InputText from 'primevue/inputtext'
import Card from 'primevue/card'
import IconField from 'primevue/iconfield'
import InputIcon from 'primevue/inputicon'
import Menu from 'primevue/menu'
import ColumnConfigDialog from './ColumnConfigDialog.vue'
import * as XLSX from 'xlsx'

const props = defineProps({
  title: { 
    type: String, 
    required: true 
  },
  entityName: { 
    type: String, 
    default: '' 
  },
  entityNameArticle: {
    type: String,
    default: ''
  },
  columns: { 
    type: Array, 
    required: true 
  },
  dataSource: { 
    type: String, 
    required: true 
  },
  storageKey: { 
    type: String, 
    required: true 
  },
  enableColumnConfig: { 
    type: Boolean, 
    default: true 
  },
  showViewButton: {
    type: Boolean,
    default: false
  },
  showCreateButton: {
    type: Boolean,
    default: true
  },
  showEditButton: {
    type: Boolean,
    default: true
  },
  showDeleteButton: {
    type: Boolean,
    default: true
  },
  showExportButton: {
    type: Boolean,
    default: false
  },
  emptyMessage: { 
    type: String, 
    default: 'Keine Daten gefunden.' 
  },
  tableProps: { 
    type: Object, 
    default: () => ({}) 
  }
})

const emit = defineEmits(['create', 'edit', 'delete', 'view', 'data-loaded'])

const toast = useToast()
const dt = ref()
const data = ref([])
const filteredData = ref([])
const loading = ref(false)
const columnConfigDialog = ref(false)
const exportMenu = ref()
const exportButton = ref()
const freezeFirstColumn = ref(false)

// Check if any filters are active
const hasActiveFilters = computed(() => {
  // Check global filter
  if (internalFilters.value.global?.value) {
    return true
  }
  
  // Check column filters
  return Object.keys(internalFilters.value).some(key => {
    if (key === 'global') return false
    const filter = internalFilters.value[key]
    if (filter?.constraints) {
      return filter.constraints.some(c => c.value !== null && c.value !== undefined && c.value !== '')
    }
    return false
  })
})

const filterCount = computed(() => {
  let count = 0
  
  // Count global filter
  if (internalFilters.value.global?.value) {
    count++
  }
  
  // Count column filters
  Object.keys(internalFilters.value).forEach(key => {
    if (key === 'global') return
    const filter = internalFilters.value[key]
    if (filter?.constraints) {
      const hasValue = filter.constraints.some(c => c.value !== null && c.value !== undefined && c.value !== '')
      if (hasValue) count++
    }
  })
  
  return count
})

// Export Menu Items
const exportItems = computed(() => [
  {
    label: 'In Zwischenablage kopieren',
    icon: 'pi pi-copy',
    command: () => exportToClipboard()
  },
  {
    label: 'Als CSV exportieren',
    icon: 'pi pi-file',
    command: () => exportToCSV()
  },
  {
    label: 'Als Excel exportieren',
    icon: 'pi pi-file-excel',
    command: () => exportToExcel()
  }
])

// Computed create button label
const createLabel = computed(() => {
  if (props.entityName) {
    // If custom article is provided, use it
    if (props.entityNameArticle) {
      return `Neu${props.entityNameArticle === 'ein' ? 'es' : 'er'} ${props.entityName}`
    }
    // Fallback: Simple heuristic
    return `Neue${props.entityName.endsWith('e') ? 'r' : 'n'} ${props.entityName}`
  }
  return 'Neu'
})

// Default table props
const defaultTableProps = {
  paginator: true,
  rows: 10,
  rowsPerPageOptions: [10, 25, 50, 100],
  rowHover: true,
  showGridlines: true,
  scrollable: true,
  scrollHeight: 'flex',
  paginatorTemplate: 'FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink CurrentPageReport RowsPerPageDropdown',
  currentPageReportTemplate: 'Zeige {first} bis {last} von {totalRecords} Einträgen'
}

// Merge user props with defaults
const mergedTableProps = computed(() => ({
  ...defaultTableProps,
  ...props.tableProps
}))

// Column Management
const availableColumns = ref([])
const visibleColumns = ref({})

const visibleColumnsOrdered = computed(() => 
  availableColumns.value.filter(col => visibleColumns.value[col.key])
)

// Filter Setup
const internalFilters = ref({
  global: { value: null, matchMode: FilterMatchMode.CONTAINS }
})

// Helper function to get nested object values
function getNestedValue(obj, path) {
  return path.split('.').reduce((current, prop) => current?.[prop], obj)
}

function loadColumnConfig() {
  const saved = localStorage.getItem(props.storageKey)
  if (saved) {
    const config = JSON.parse(saved)
    
    // Load filters if available - will be applied in onMounted
    if (config.filters) {
      // Deep merge filters into internalFilters
      Object.keys(config.filters).forEach(key => {
        const savedFilter = config.filters[key]
        if (savedFilter) {
          // Handle both constraint-based (menu) and value-based (global) filters
          if (savedFilter.constraints) {
            // Menu filter with constraints
            const hasValue = savedFilter.constraints.some(c => c.value !== null && c.value !== undefined && c.value !== '')
            if (hasValue) {
              internalFilters.value[key] = JSON.parse(JSON.stringify(savedFilter))
            }
          } else if (key === 'global' && (savedFilter.value !== null && savedFilter.value !== undefined && savedFilter.value !== '')) {
            // Global filter
            internalFilters.value[key] = { ...savedFilter }
          }
        }
      })
    }
    
    // Load freeze first column setting
    if (config.freezeFirstColumn !== undefined) {
      freezeFirstColumn.value = config.freezeFirstColumn
    }
    
    // Handle both old and new format
    if (config.visibility) {
      // Apply saved order
      if (config.order) {
        const ordered = []
        config.order.forEach(key => {
          const col = props.columns.find(c => c.key === key)
          if (col) ordered.push(col)
        })
        // Add new columns not in saved order
        props.columns.forEach(col => {
          if (!ordered.find(c => c.key === col.key)) {
            ordered.push(col)
          }
        })
        availableColumns.value = ordered
      } else {
        availableColumns.value = [...props.columns]
      }
      return config.visibility
    } else {
      // Old format - just visibility object
      availableColumns.value = [...props.columns]
      return config
    }
  }
  
  // Default: Use column defaults
  availableColumns.value = [...props.columns]
  return props.columns.reduce((acc, col) => {
    acc[col.key] = col.default !== false
    return acc
  }, {})
}

function saveColumnConfig() {
  const config = {
    visibility: visibleColumns.value,
    order: availableColumns.value.map(col => col.key),
    filters: internalFilters.value,
    freezeFirstColumn: freezeFirstColumn.value
  }
  localStorage.setItem(props.storageKey, JSON.stringify(config))
  columnConfigDialog.value = false
  
  toast.add({
    severity: 'success',
    summary: 'Gespeichert',
    detail: 'Spaltenkonfiguration wurde gespeichert',
    life: 3000
  })
}

// Save filters to localStorage whenever they change
function saveFilters() {
  const saved = localStorage.getItem(props.storageKey)
  const config = saved ? JSON.parse(saved) : { 
    visibility: visibleColumns.value,
    order: availableColumns.value.map(col => col.key)
  }
  
  // Clean up filters - only save non-empty values
  const cleanedFilters = {}
  Object.keys(internalFilters.value).forEach(key => {
    const filter = internalFilters.value[key]
    if (filter) {
      if (filter.constraints) {
        // Menu filter - only save if has actual values
        const hasValue = filter.constraints.some(c => c.value !== null && c.value !== undefined && c.value !== '')
        if (hasValue) {
          cleanedFilters[key] = filter
        }
      } else if (key === 'global' && filter.value !== null && filter.value !== undefined && filter.value !== '') {
        // Global filter
        cleanedFilters[key] = filter
      }
    }
  })
  
  config.filters = cleanedFilters
  localStorage.setItem(props.storageKey, JSON.stringify(config))
}

function clearAllFilters() {
  // Reset global filter
  internalFilters.value.global = { value: null, matchMode: FilterMatchMode.CONTAINS }
  
  // Reset all column filters
  Object.keys(internalFilters.value).forEach(key => {
    if (key !== 'global' && internalFilters.value[key]?.constraints) {
      internalFilters.value[key].constraints = [{ value: null, matchMode: FilterMatchMode.STARTS_WITH }]
    }
  })
  
  // Clear filtered data
  filteredData.value = []
  
  // Save cleared filters
  saveFilters()
  
  toast.add({
    severity: 'info',
    summary: 'Filter zurückgesetzt',
    detail: 'Alle Filter wurden entfernt',
    life: 3000
  })
}

async function loadData(params = {}) {
  loading.value = true
  try {
    const url = new URL(props.dataSource, window.location.origin)
    url.searchParams.append('itemsPerPage', '5000')
    
    // Add custom params
    Object.entries(params).forEach(([key, value]) => {
      if (value !== null && value !== undefined) {
        url.searchParams.append(key, value)
      }
    })
    
    const response = await fetch(url, { 
      credentials: 'include',
      headers: {
        'Accept': 'application/ld+json'
      }
    })
    
    if (!response.ok) {
      const error = await response.json()
      throw new Error(error['hydra:description'] || 'Fehler beim Laden der Daten')
    }
    
    const json = await response.json()
    data.value = json['hydra:member'] || json.member || json
    emit('data-loaded', data.value)
  } catch (error) {
    console.error('Error loading data:', error)
    toast.add({
      severity: 'error',
      summary: 'Fehler',
      detail: error.message || 'Daten konnten nicht geladen werden',
      life: 3000
    })
  } finally {
    loading.value = false
  }
}

// Track filtered data from DataTable
function onFilter(event) {
  // PrimeVue's @filter event provides filteredValue
  filteredData.value = event.filteredValue || []
  
  // Save filters to localStorage
  saveFilters()
}

// Export Functions
function getExportData() {
  // Get only visible columns
  const visibleCols = visibleColumnsOrdered.value
  
  // Use filtered data if available, otherwise use all data
  const dataToExport = filteredData.value.length > 0 || Object.keys(internalFilters.value).some(k => k !== 'global' && internalFilters.value[k]?.value) || internalFilters.value.global?.value
    ? filteredData.value 
    : data.value
  
  // Helper function to format objects for export
  const formatObject = (obj) => {
    if (!obj || typeof obj !== 'object') return obj
    
    // For contact persons, format as "Salutation FirstName LastName (Position)"
    if (obj.firstName && obj.lastName) {
      const parts = []
      if (obj.salutation) parts.push(obj.salutation)
      if (obj.firstName) parts.push(obj.firstName)
      if (obj.lastName) parts.push(obj.lastName)
      if (obj.position) parts.push(`(${obj.position})`)
      return parts.join(' ')
    }
    
    // For other objects, try to find a meaningful representation
    if (obj.name) return obj.name
    if (obj.title) return obj.title
    if (obj.label) return obj.label
    
    // Fallback: return first non-id property value
    const keys = Object.keys(obj).filter(k => !k.startsWith('@') && k !== 'id')
    if (keys.length > 0) return obj[keys[0]]
    
    return ''
  }
  
  // Prepare export data from filtered data
  return dataToExport.map(row => {
    const exportRow = {}
    visibleCols.forEach(col => {
      // Check if column has custom export formatter
      if (col.exportFormatter && typeof col.exportFormatter === 'function') {
        exportRow[col.label] = col.exportFormatter(row)
        return
      }
      
      const value = getNestedValue(row, col.field || col.key)
      // Format arrays (e.g., contactPersons)
      if (Array.isArray(value)) {
        exportRow[col.label] = value.map(v => formatObject(v)).filter(v => v).join(', ')
      } else if (typeof value === 'boolean') {
        exportRow[col.label] = value ? 'Ja' : 'Nein'
      } else if (value instanceof Date) {
        exportRow[col.label] = value.toLocaleDateString('de-DE')
      } else if (typeof value === 'object' && value !== null) {
        exportRow[col.label] = formatObject(value)
      } else {
        exportRow[col.label] = value ?? ''
      }
    })
    return exportRow
  })
}

function exportToClipboard() {
  try {
    const exportData = getExportData()
    
    // Convert to TSV (Tab-Separated Values) for better Excel paste compatibility
    const headers = Object.keys(exportData[0] || {})
    const tsv = [
      headers.join('\t'),
      ...exportData.map(row => headers.map(h => row[h]).join('\t'))
    ].join('\n')
    
    navigator.clipboard.writeText(tsv).then(() => {
      toast.add({
        severity: 'success',
        summary: 'Kopiert',
        detail: `${exportData.length} Zeilen in die Zwischenablage kopiert`,
        life: 3000
      })
    })
  } catch (error) {
    console.error('Export error:', error)
    toast.add({
      severity: 'error',
      summary: 'Fehler',
      detail: 'Fehler beim Kopieren in die Zwischenablage',
      life: 3000
    })
  }
}

function exportToCSV() {
  try {
    const exportData = getExportData()
    
    if (exportData.length === 0) {
      toast.add({
        severity: 'warn',
        summary: 'Keine Daten',
        detail: 'Keine Daten zum Exportieren vorhanden',
        life: 3000
      })
      return
    }
    
    // Convert to CSV
    const headers = Object.keys(exportData[0])
    const csvContent = [
      headers.join(';'),
      ...exportData.map(row => 
        headers.map(h => {
          const value = row[h]
          // Escape quotes and wrap in quotes if contains comma or newline
          if (typeof value === 'string' && (value.includes(';') || value.includes('\n') || value.includes('"'))) {
            return `"${value.replace(/"/g, '""')}"`
          }
          return value
        }).join(';')
      )
    ].join('\n')
    
    // Add BOM for Excel UTF-8 compatibility
    const BOM = '\uFEFF'
    const blob = new Blob([BOM + csvContent], { type: 'text/csv;charset=utf-8;' })
    const link = document.createElement('a')
    const url = URL.createObjectURL(blob)
    
    link.setAttribute('href', url)
    link.setAttribute('download', `${props.title.replace(/\s+/g, '_')}_${new Date().toISOString().split('T')[0]}.csv`)
    link.style.visibility = 'hidden'
    document.body.appendChild(link)
    link.click()
    document.body.removeChild(link)
    
    toast.add({
      severity: 'success',
      summary: 'Exportiert',
      detail: `${exportData.length} Zeilen als CSV exportiert`,
      life: 3000
    })
  } catch (error) {
    console.error('Export error:', error)
    toast.add({
      severity: 'error',
      summary: 'Fehler',
      detail: 'Fehler beim CSV-Export',
      life: 3000
    })
  }
}

function exportToExcel() {
  try {
    const exportData = getExportData()
    
    if (exportData.length === 0) {
      toast.add({
        severity: 'warn',
        summary: 'Keine Daten',
        detail: 'Keine Daten zum Exportieren vorhanden',
        life: 3000
      })
      return
    }
    
    // Create worksheet
    const ws = XLSX.utils.json_to_sheet(exportData)
    
    // Auto-size columns
    const colWidths = Object.keys(exportData[0]).map(key => ({
      wch: Math.max(
        key.length,
        ...exportData.map(row => String(row[key] ?? '').length)
      )
    }))
    ws['!cols'] = colWidths
    
    // Create workbook
    const wb = XLSX.utils.book_new()
    XLSX.utils.book_append_sheet(wb, ws, props.title.substring(0, 31)) // Excel sheet name max 31 chars
    
    // Generate Excel file
    XLSX.writeFile(wb, `${props.title.replace(/\s+/g, '_')}_${new Date().toISOString().split('T')[0]}.xlsx`)
    
    toast.add({
      severity: 'success',
      summary: 'Exportiert',
      detail: `${exportData.length} Zeilen als Excel exportiert`,
      life: 3000
    })
  } catch (error) {
    console.error('Export error:', error)
    toast.add({
      severity: 'error',
      summary: 'Fehler',
      detail: 'Fehler beim Excel-Export',
      life: 3000
    })
  }
}

// Watch for changes in global filter to save automatically
watch(() => internalFilters.value.global?.value, () => {
  saveFilters()
}, { deep: true })

// Initialize
onMounted(() => {
  visibleColumns.value = loadColumnConfig()
  
  // Initialize column-specific filters with operator structure for menu mode
  props.columns.forEach(col => {
    if (col.filterable !== false && !internalFilters.value[col.key]) {
      internalFilters.value[col.key] = {
        operator: FilterOperator.AND,
        constraints: [{ value: null, matchMode: FilterMatchMode.STARTS_WITH }]
      }
    }
  })
  
  // Auto-load data
  loadData()
})

// Expose loadData for parent component
defineExpose({ loadData })
</script>
