// TODO: Split into sub-components — see docs/TECHNICAL_DEBT.md
// Current size: 822 lines. Priority: Medium
'use client'

import { useState, useCallback, useMemo, useEffect } from'react'
import {
 Search,
 Upload,
 Download,
 Pencil,
 Trash2,
 FileText,
 FileImage,
 FileSpreadsheet,
 FilePieChart,
 File,
 ChevronLeft,
 ChevronRight,
 Check,
 X,
} from'lucide-react'
import { createClient } from'@/lib/supabase/client'
import { resolveSearchEmptyState } from'@/lib/ui/search-empty-state'
import type { Document, SupplierMasterData, DepartmentMasterData } from'@/lib/repository-types'
import { DOCUMENT_TYPES } from'@/lib/repository-types'
import UploadDialog from'./upload-dialog'
import DocumentDetailDrawer from'./document-detail-drawer'
import MultiSelectField from'./multi-select-field'

interface Project {
 id: string
 supplier_name: string
 visit_date: string
 product_name: string | null
 plant_location: string | null
}

interface Props {
 projects: Project[]
 initialDocuments: Document[]
 initialProjectId: string | null
}

// Map from document_id to supplier names and dept names (for display)
interface DocRelations {
 supplierNames: string[]
 deptNames: string[]
}

interface DocSupplierLink {
 document_id: string
 supplier_id: string
 supplier_master_data: { supplier_name: string }[] | null
}

interface DocDepartmentLink {
 document_id: string
 department_id: string
 department_master_data: { department_name: string; department_code: string }[] | null
}

const PAGE_SIZE = 20

function formatFileSize(bytes: number | null): string {
 if (bytes === null) return'—'
 if (bytes < 1024) return `${bytes} B`
 if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`
 return `${(bytes / (1024 * 1024)).toFixed(1)} MB`
}

function formatDate(iso: string): string {
 return new Date(iso).toLocaleDateString('de-DE', {
 day:'2-digit',
 month:'2-digit',
 year:'numeric',
 })
}

function getMimeIcon(mimeType: string | null) {
 if (!mimeType) return <File size={15} className="text-muted-foreground"/>
 if (mimeType.startsWith('image/')) return <FileImage size={15} className="text-primary"/>
 if (mimeType.includes('spreadsheet') || mimeType.includes('excel') || mimeType ==='text/csv')
 return <FileSpreadsheet size={15} className="text-success"/>
 if (mimeType ==='application/pdf') return <FilePieChart size={15} className="text-destructive"/>
 return <FileText size={15} className="text-muted-foreground"/>
}

type FileTypeFilter ='all'|'pdf'|'excel'|'image'|'other'

function matchesFileType(doc: Document, filter: FileTypeFilter): boolean {
 if (filter ==='all') return true
 const m = doc.mime_type ??''
 if (filter ==='pdf') return m ==='application/pdf'
 if (filter ==='excel') return m.includes('spreadsheet') || m.includes('excel') || m ==='text/csv'
 if (filter ==='image') return m.startsWith('image/')
 if (filter ==='other')
 return !['application/pdf'].includes(m) && !m.includes('spreadsheet') && !m.includes('excel') && m !=='text/csv'&& !m.startsWith('image/')
 return true
}

// Renders up to 2 names + overflow chip
function NameChips({ names, colorClass }: { names: string[]; colorClass: string }) {
 if (names.length === 0) return <span className="text-xs text-muted-foreground">—</span>
 const visible = names.slice(0, 2)
 const overflow = names.length - 2
 return (
 <div className="flex flex-wrap gap-1">
 {visible.map((n) => (
 <span key={n} className={`text-[10px] rounded-full px-2 py-0.5 font-medium ${colorClass}`}>{n}</span>
 ))}
 {overflow > 0 && (
 <span className="text-[10px] rounded-full px-2 py-0.5 font-medium bg-background text-muted-foreground border border-border">+{overflow}</span>
 )}
 </div>
 )
}

export default function ProjectDocumentsClient({
 projects,
 initialDocuments,
 initialProjectId,
}: Props) {
 const [selectedProjectId, setSelectedProjectId] = useState<string | null>(initialProjectId)
 const [documents, setDocuments] = useState<Document[]>(initialDocuments)
 const [loadingDocs, setLoadingDocs] = useState(false)
 const [projectSearch, setProjectSearch] = useState('')
 const [docSearch, setDocSearch] = useState('')
 const [typeFilter, setTypeFilter] = useState<string>('')
 const [fileTypeFilter, setFileTypeFilter] = useState<FileTypeFilter>('all')
 const [dateFrom, setDateFrom] = useState('')
 const [dateTo, setDateTo] = useState('')
 const [supplierFilter, setSupplierFilter] = useState<string[]>([])
 const [deptFilter, setDeptFilter] = useState<string[]>([])
 const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set())
 const [page, setPage] = useState(1)
 const [showUpload, setShowUpload] = useState(false)
 const [detailDoc, setDetailDoc] = useState<Document | null>(null)
 const [editingDoc, setEditingDoc] = useState<Document | null>(null)
 const [editTitle, setEditTitle] = useState('')
 const [editDocType, setEditDocType] = useState('')
 const [editDescription, setEditDescription] = useState('')
 const [savingEdit, setSavingEdit] = useState(false)
 const [deleteConfirmId, setDeleteConfirmId] = useState<string | null>(null)
 const [deleting, setDeleting] = useState(false)
 const [bulkDeleteConfirm, setBulkDeleteConfirm] = useState(false)
 const supabase = useMemo(() => createClient(), [])

 // Relations: map from docId → { supplierNames, deptNames }
 const [docRelations, setDocRelations] = useState<Map<string, DocRelations>>(new Map())

 // Master data for filters
 const [allSuppliers, setAllSuppliers] = useState<SupplierMasterData[]>([])
 const [allDepts, setAllDepts] = useState<DepartmentMasterData[]>([])
 const [masterDataLoaded, setMasterDataLoaded] = useState(false)

 // Supplier/dept IDs that have docs in the active document set (for filtering)
 const [docSupplierLinks, setDocSupplierLinks] = useState<Map<string, string[]>>(new Map()) // docId → supplierIds
 const [docDeptLinks, setDocDeptLinks] = useState<Map<string, string[]>>(new Map()) // docId → deptIds

 const selectedProject = projects.find((p) => p.id === selectedProjectId) ?? null

 const filteredProjects = projectSearch.trim()
 ? projects.filter((p) =>
 p.supplier_name.toLowerCase().includes(projectSearch.toLowerCase())
 )
 : projects

 async function loadMasterData() {
 if (masterDataLoaded) return
 const [{ data: sData }, { data: dData }] = await Promise.all([
 supabase.from('supplier_master_data').select('id, supplier_number, supplier_name, supplier_location, plant, country, city, is_active, created_at, updated_at, created_by, updated_by').eq('is_active', true).order('supplier_name'),
 supabase.from('department_master_data').select('id, department_code, department_name, organization_area, is_active, created_at, updated_at').eq('is_active', true).order('department_name'),
 ])
 setAllSuppliers((sData as SupplierMasterData[]) ?? [])
 setAllDepts((dData as DepartmentMasterData[]) ?? [])
 setMasterDataLoaded(true)
 }

 async function loadRelationsForDocs(docIds: string[]) {
 if (docIds.length === 0) return
 const [{ data: supLinks }, { data: deptLinks }] = await Promise.all([
 supabase.from('document_suppliers').select('document_id, supplier_id, supplier_master_data(supplier_name)').in('document_id', docIds),
 supabase.from('document_departments').select('document_id, department_id, department_master_data(department_name, department_code)').in('document_id', docIds),
 ])

 const newRelations = new Map<string, DocRelations>()
 const newSupLinks = new Map<string, string[]>()
 const newDeptLinks = new Map<string, string[]>()

 for (const link of (supLinks ?? []) as DocSupplierLink[]) {
 const docId = link.document_id
 const suppId = link.supplier_id
 const name = link.supplier_master_data?.[0]?.supplier_name
 if (!newRelations.has(docId)) newRelations.set(docId, { supplierNames: [], deptNames: [] })
 if (name) newRelations.get(docId)!.supplierNames.push(name)
 if (!newSupLinks.has(docId)) newSupLinks.set(docId, [])
 newSupLinks.get(docId)!.push(suppId)
 }

 for (const link of (deptLinks ?? []) as DocDepartmentLink[]) {
 const docId = link.document_id
 const deptId = link.department_id
 const name = link.department_master_data?.[0]?.department_name
 if (!newRelations.has(docId)) newRelations.set(docId, { supplierNames: [], deptNames: [] })
 if (name) newRelations.get(docId)!.deptNames.push(name)
 if (!newDeptLinks.has(docId)) newDeptLinks.set(docId, [])
 newDeptLinks.get(docId)!.push(deptId)
 }

 setDocRelations((prev) => {
 const merged = new Map(prev)
 newRelations.forEach((v, k) => merged.set(k, v))
 return merged
 })
 setDocSupplierLinks((prev) => {
 const merged = new Map(prev)
 newSupLinks.forEach((v, k) => merged.set(k, v))
 return merged
 })
 setDocDeptLinks((prev) => {
 const merged = new Map(prev)
 newDeptLinks.forEach((v, k) => merged.set(k, v))
 return merged
 })
 }

 async function loadDocuments(projectId: string) {
 setLoadingDocs(true)
 setSelectedIds(new Set())
 setPage(1)
 const { data } = await supabase
 .from('documents')
 .select('*')
 .eq('project_id', projectId)
 .eq('is_deleted', false)
 .order('created_at', { ascending: false })
 const docs = (data as Document[]) ?? []
 setDocuments(docs)
 setLoadingDocs(false)

 void loadMasterData()
 void loadRelationsForDocs(docs.map((d) => d.id))
 }

 function handleProjectClick(projectId: string) {
 if (projectId === selectedProjectId) return
 setSelectedProjectId(projectId)
 loadDocuments(projectId)
 }

 const filteredDocs = useMemo(() => {
 return documents.filter((d) => {
 if (docSearch.trim() && !d.title.toLowerCase().includes(docSearch.toLowerCase()) && !d.original_filename.toLowerCase().includes(docSearch.toLowerCase())) return false
 if (typeFilter && d.document_type !== typeFilter) return false
 if (!matchesFileType(d, fileTypeFilter)) return false
 if (dateFrom && d.created_at < dateFrom) return false
 if (dateTo && d.created_at.slice(0, 10) > dateTo) return false

 // Supplier filter: doc must have at least one of the selected supplier IDs
 if (supplierFilter.length > 0) {
 const docSupIds = docSupplierLinks.get(d.id) ?? []
 if (!supplierFilter.some((id) => docSupIds.includes(id))) return false
 }

 // Dept filter: doc must have at least one of the selected dept IDs
 if (deptFilter.length > 0) {
 const docDeptIds = docDeptLinks.get(d.id) ?? []
 if (!deptFilter.some((id) => docDeptIds.includes(id))) return false
 }

 return true
 })
 }, [documents, docSearch, typeFilter, fileTypeFilter, dateFrom, dateTo, supplierFilter, deptFilter, docSupplierLinks, docDeptLinks])

 const totalPages = Math.max(1, Math.ceil(filteredDocs.length / PAGE_SIZE))
 const pagedDocs = filteredDocs.slice((page - 1) * PAGE_SIZE, page * PAGE_SIZE)

 function toggleSelect(id: string) {
 setSelectedIds((prev) => {
 const next = new Set(prev)
 if (next.has(id)) next.delete(id)
 else next.add(id)
 return next
 })
 }

 function toggleSelectAll() {
 if (selectedIds.size === pagedDocs.length) {
 setSelectedIds(new Set())
 } else {
 setSelectedIds(new Set(pagedDocs.map((d) => d.id)))
 }
 }

 async function handleDownload(doc: Document) {
 const { data, error } = await supabase.storage
 .from('documents')
 .createSignedUrl(doc.storage_key, 60)
 if (error || !data?.signedUrl) return
 const a = document.createElement('a')
 a.href = data.signedUrl
 a.download = doc.original_filename
 a.click()
 }

 function startEdit(doc: Document) {
 setEditingDoc(doc)
 setEditTitle(doc.title)
 setEditDocType(doc.document_type ??'')
 setEditDescription(doc.description ??'')
 }

 async function saveEdit() {
 if (!editingDoc) return
 setSavingEdit(true)
 const { data, error } = await supabase
 .from('documents')
 .update({
 title: editTitle.trim() || editingDoc.title,
 document_type: editDocType || null,
 description: editDescription || null,
 })
 .eq('id', editingDoc.id)
 .select()
 .single()
 if (!error && data) {
 setDocuments((prev) =>
 prev.map((d) => (d.id === editingDoc.id ? (data as Document) : d))
 )
 }
 setSavingEdit(false)
 setEditingDoc(null)
 }

 async function confirmDelete(docId: string) {
 setDeleting(true)
 await supabase.from('documents').update({ is_deleted: true }).eq('id', docId)
 setDocuments((prev) => prev.filter((d) => d.id !== docId))
 setDeleteConfirmId(null)
 setDeleting(false)
 }

 async function confirmBulkDelete() {
 setDeleting(true)
 const ids = Array.from(selectedIds)
 await supabase.from('documents').update({ is_deleted: true }).in('id', ids)
 setDocuments((prev) => prev.filter((d) => !selectedIds.has(d.id)))
 setSelectedIds(new Set())
 setBulkDeleteConfirm(false)
 setDeleting(false)
 }

 function handleUploadSuccess(doc: Document) {
 setDocuments((prev) => [doc, ...prev])
 setShowUpload(false)
 void loadRelationsForDocs([doc.id])
 }

 const supplierFilterItems = allSuppliers.map((s) => ({
 id: s.id,
 label: s.supplier_name,
 sublabel: s.supplier_number,
 }))

 const deptFilterItems = allDepts.map((d) => ({
 id: d.id,
 label: d.department_name,
 sublabel: d.department_code,
 }))

 return (
 <div className="flex h-[calc(100dvh-8rem)] gap-0 bg-card border border-border rounded-lg overflow-hidden">
 {/* Left panel — project list */}
 <aside className="w-64 shrink-0 border-r border-border flex flex-col bg-background">
 <div className="p-3 border-b border-border">
 <div className="relative">
 <Search size={13} className="absolute left-2.5 top-1/2 -translate-y-1/2 text-muted-foreground"/>
 <input
 type="search"
 value={projectSearch}
 onChange={(e) => setProjectSearch(e.target.value)}
 placeholder="Projekte suchen…"
 className="w-full pl-8 pr-3 py-1.5 text-xs rounded border border-border bg-card focus:outline-none focus:ring-1 focus:ring-primary/30 focus:border-primary"
 />
 </div>
 </div>
 <div className="flex-1 overflow-y-auto">
 {filteredProjects.length === 0 ? (
 <p className="text-xs text-muted-foreground px-4 py-6 text-center">Keine Projekte</p>
 ) : (
 filteredProjects.map((p) => {
 const active = p.id === selectedProjectId
 return (
 <button
 key={p.id}
 onClick={() => handleProjectClick(p.id)}
 className={`w-full text-left px-4 py-3 border-b border-border transition-colors ${
 active
 ?'bg-primary text-white'
 :'hover:bg-secondary text-foreground'
 }`}
 >
 <p className={`text-xs font-semibold truncate ${active ?'text-white':'text-foreground'}`}>
 {p.supplier_name}
 </p>
 <p className={`text-[10px] mt-0.5 ${active ?'text-white/70':'text-muted-foreground'}`}>
 {new Date(p.visit_date).toLocaleDateString('de-DE')}
 </p>
 </button>
 )
 })
 )}
 </div>
 </aside>

 {/* Right panel — document table */}
 <div className="flex-1 min-w-0 flex flex-col">
 {/* Panel header */}
 <div className="flex items-center justify-between px-5 py-3 border-b border-border bg-card shrink-0">
 <div>
 <p className="font-semibold text-sm text-foreground">
 {selectedProject?.supplier_name ??'Kein Projekt gewählt'}
 </p>
 {selectedProject && (
 <p className="text-xs text-muted-foreground">
 {new Date(selectedProject.visit_date).toLocaleDateString('de-DE')}
 {selectedProject.plant_location ? ` · ${selectedProject.plant_location}` :''}
 </p>
 )}
 </div>
 {selectedProjectId && (
 <button
 onClick={() => setShowUpload(true)}
 className="inline-flex items-center gap-1.5 bg-primary text-white text-xs font-medium px-3 py-2 rounded hover:bg-primary-dark transition-colors"
 >
 <Upload size={13} />
 Hochladen
 </button>
 )}
 </div>

 {/* Filter bar */}
 <div className="flex flex-wrap items-start gap-2 px-5 py-2.5 border-b border-border bg-background shrink-0">
 <div className="relative">
 <Search size={12} className="absolute left-2.5 top-1/2 -translate-y-1/2 text-muted-foreground"/>
 <input
 type="search"
 value={docSearch}
 onChange={(e) => { setDocSearch(e.target.value); setPage(1) }}
 placeholder="Titel oder Dateiname…"
 className="pl-7 pr-3 py-1.5 text-xs rounded border border-border bg-card focus:outline-none focus:ring-1 focus:ring-primary/30 focus:border-primary w-40"
 />
 </div>
 <select
 value={typeFilter}
 onChange={(e) => { setTypeFilter(e.target.value); setPage(1) }}
 className="text-xs rounded border border-border bg-card px-2 py-1.5 focus:outline-none focus:ring-1 focus:ring-primary/30"
 >
 <option value="">Alle Typen</option>
 {DOCUMENT_TYPES.map((t) => (
 <option key={t} value={t}>{t}</option>
 ))}
 </select>
 <select
 value={fileTypeFilter}
 onChange={(e) => { setFileTypeFilter(e.target.value as FileTypeFilter); setPage(1) }}
 className="text-xs rounded border border-border bg-card px-2 py-1.5 focus:outline-none focus:ring-1 focus:ring-primary/30"
 >
 <option value="all">Alle Dateien</option>
 <option value="pdf">PDF</option>
 <option value="excel">Excel / CSV</option>
 <option value="image">Bilder</option>
 <option value="other">Sonstige</option>
 </select>
 <input
 type="date"
 value={dateFrom}
 onChange={(e) => { setDateFrom(e.target.value); setPage(1) }}
 className="text-xs rounded border border-border bg-card px-2 py-1.5 focus:outline-none focus:ring-1 focus:ring-primary/30"
 />
 <span className="text-xs text-muted-foreground py-1.5">–</span>
 <input
 type="date"
 value={dateTo}
 onChange={(e) => { setDateTo(e.target.value); setPage(1) }}
 className="text-xs rounded border border-border bg-card px-2 py-1.5 focus:outline-none focus:ring-1 focus:ring-primary/30"
 />
 {masterDataLoaded && allSuppliers.length > 0 && (
 <div className="w-48">
 <MultiSelectField
 label=""
 placeholder="Lieferant filtern…"
 items={supplierFilterItems}
 selectedIds={supplierFilter}
 onChange={(ids) => { setSupplierFilter(ids); setPage(1) }}
 />
 </div>
 )}
 {masterDataLoaded && allDepts.length > 0 && (
 <div className="w-48">
 <MultiSelectField
 label=""
 placeholder="Abteilung filtern…"
 items={deptFilterItems}
 selectedIds={deptFilter}
 onChange={(ids) => { setDeptFilter(ids); setPage(1) }}
 />
 </div>
 )}
 </div>

 {/* Bulk actions bar */}
 {selectedIds.size > 0 && (
 <div className="flex items-center gap-3 px-5 py-2 bg-secondary border-b border-primary/20 shrink-0">
 <span className="text-xs font-medium text-primary">
 {selectedIds.size} ausgewählt
 </span>
 <button
 onClick={() => setBulkDeleteConfirm(true)}
 className="inline-flex items-center gap-1 text-xs text-destructive hover:text-destructive/80 font-medium"
 >
 <Trash2 size={13} />
 Auswahl löschen
 </button>
 <button
 onClick={() => setSelectedIds(new Set())}
 className="text-xs text-muted-foreground hover:text-foreground ml-auto"
 >
 Abbrechen
 </button>
 </div>
 )}

 {/* Table */}
 <div className="flex-1 overflow-auto">
 {loadingDocs ? (
 <div className="flex items-center justify-center py-20 text-muted-foreground text-sm">
 Lade Dokumente…
 </div>
 ) : !selectedProjectId ? (
 <div className="flex flex-col items-center justify-center py-20 text-muted-foreground">
 <FileText size={36} className="opacity-20 mb-3"/>
 <p className="text-sm font-medium">Projekt auswählen</p>
 <p className="text-xs mt-1">Wählen Sie links ein Projekt aus.</p>
 </div>
 ) : pagedDocs.length === 0 ? (
 <div className="flex flex-col items-center justify-center py-20 text-muted-foreground">
 <FileText size={36} className="opacity-20 mb-3"/>
 {resolveSearchEmptyState(false, documents.length) ==='no-results'? (
 <>
 <p className="text-sm font-medium">Keine Treffer</p>
 <p className="text-xs mt-1">Keine Dokumente für die aktuellen Filter.</p>
 <button
 onClick={() => { setDocSearch(''); setTypeFilter(''); setFileTypeFilter('all'); setDateFrom(''); setDateTo(''); setSupplierFilter([]); setDeptFilter([]); setPage(1) }}
 className="mt-4 inline-flex items-center gap-1.5 bg-background border border-border text-foreground text-xs font-medium px-3 py-2 rounded hover:bg-secondary transition-colors"
 >
 Filter zurücksetzen
 </button>
 </>
 ) : (
 <>
 <p className="text-sm font-medium">Keine Dokumente</p>
 <p className="text-xs mt-1">Laden Sie das erste Dokument hoch.</p>
 <button
 onClick={() => setShowUpload(true)}
 className="mt-4 inline-flex items-center gap-1.5 bg-primary text-white text-xs font-medium px-3 py-2 rounded hover:bg-primary-dark transition-colors"
 >
 <Upload size={13} />
 Hochladen
 </button>
 </>
 )}
 </div>
 ) : (
 <table className="w-full text-sm min-w-[700px]">
 <thead className="sticky top-0 bg-background z-10">
 <tr className="border-b border-border text-xs text-muted-foreground font-medium">
 <th className="px-4 py-3 text-left w-8">
 <input
 type="checkbox"
 checked={selectedIds.size === pagedDocs.length && pagedDocs.length > 0}
 onChange={toggleSelectAll}
 className="rounded border-border text-primary focus:ring-primary/30"
 />
 </th>
 <th className="px-2 py-3 text-left w-6"></th>
 <th className="px-2 py-3 text-left">Titel</th>
 <th className="px-2 py-3 text-left hidden sm:table-cell">Typ</th>
 <th className="px-2 py-3 text-left hidden lg:table-cell">Lieferanten</th>
 <th className="px-2 py-3 text-left hidden lg:table-cell">Abteilungen</th>
 <th className="px-2 py-3 text-right hidden md:table-cell">Größe</th>
 <th className="px-2 py-3 text-left hidden lg:table-cell">Datum</th>
 <th className="px-4 py-3 text-right">Aktionen</th>
 </tr>
 </thead>
 <tbody className="divide-y divide-border">
 {pagedDocs.map((doc) => {
 const isEditing = editingDoc?.id === doc.id
 const relations = docRelations.get(doc.id)
 return (
 <tr key={doc.id} className={`hover:bg-background transition-colors ${selectedIds.has(doc.id) ?'bg-secondary':''}`}>
 <td className="px-4 py-3">
 <input
 type="checkbox"
 checked={selectedIds.has(doc.id)}
 onChange={() => toggleSelect(doc.id)}
 className="rounded border-border text-primary focus:ring-primary/30"
 />
 </td>
 <td className="px-2 py-3">{getMimeIcon(doc.mime_type)}</td>
 <td className="px-2 py-3 max-w-[180px]">
 {isEditing ? (
 <input
 value={editTitle}
 onChange={(e) => setEditTitle(e.target.value)}
 className="w-full text-xs border border-primary rounded px-2 py-1 focus:outline-none"
 autoFocus
 />
 ) : (
 <p className="font-medium text-foreground truncate text-xs">{doc.title}</p>
 )}
 </td>
 <td className="px-2 py-3 hidden sm:table-cell">
 {isEditing ? (
 <select
 value={editDocType}
 onChange={(e) => setEditDocType(e.target.value)}
 className="text-xs border border-border rounded px-1.5 py-1 focus:outline-none focus:border-primary"
 >
 <option value="">—</option>
 {DOCUMENT_TYPES.map((t) => <option key={t} value={t}>{t}</option>)}
 </select>
 ) : doc.document_type ? (
 <span className="text-xs bg-secondary text-primary rounded-full px-2 py-0.5 font-medium">
 {doc.document_type}
 </span>
 ) : (
 <span className="text-xs text-muted-foreground">—</span>
 )}
 </td>
 <td className="px-2 py-3 hidden lg:table-cell">
 <NameChips
 names={relations?.supplierNames ?? []}
 colorClass="bg-secondary text-primary"
 />
 </td>
 <td className="px-2 py-3 hidden lg:table-cell">
 <NameChips
 names={relations?.deptNames ?? []}
 colorClass="bg-amber-50 text-amber-700"
 />
 </td>
 <td className="px-2 py-3 text-xs text-right font-mono text-muted-foreground hidden md:table-cell">
 {formatFileSize(doc.file_size)}
 </td>
 <td className="px-2 py-3 text-xs text-muted-foreground hidden lg:table-cell">
 {formatDate(doc.created_at)}
 </td>
 <td className="px-4 py-3 text-right">
 <div className="flex items-center justify-end gap-1">
 {isEditing ? (
 <>
 <button
 onClick={saveEdit}
 disabled={savingEdit}
 className="p-1.5 rounded hover:bg-secondary text-success transition-colors"
 title="Speichern"
 >
 <Check size={13} />
 </button>
 <button
 onClick={() => setEditingDoc(null)}
 className="p-1.5 rounded hover:bg-background text-muted-foreground transition-colors"
 title="Abbrechen"
 >
 <X size={13} />
 </button>
 </>
 ) : (
 <>
 <button
 onClick={() => setDetailDoc(doc)}
 className="p-1.5 rounded hover:bg-secondary text-muted-foreground hover:text-primary transition-colors"
 title="Details"
 >
 <Search size={13} />
 </button>
 <button
 onClick={() => handleDownload(doc)}
 className="p-1.5 rounded hover:bg-secondary text-primary transition-colors"
 title="Herunterladen"
 >
 <Download size={13} />
 </button>
 <button
 onClick={() => startEdit(doc)}
 className="p-1.5 rounded hover:bg-secondary text-muted-foreground hover:text-foreground transition-colors"
 title="Bearbeiten"
 >
 <Pencil size={13} />
 </button>
 <button
 onClick={() => setDeleteConfirmId(doc.id)}
 className="p-1.5 rounded hover:bg-red-50 text-muted-foreground hover:text-destructive transition-colors"
 title="Löschen"
 >
 <Trash2 size={13} />
 </button>
 </>
 )}
 </div>
 </td>
 </tr>
 )
 })}
 </tbody>
 </table>
 )}
 </div>

 {/* Pagination */}
 {totalPages > 1 && (
 <div className="flex items-center justify-between px-5 py-3 border-t border-border bg-card shrink-0">
 <p className="text-xs text-muted-foreground">
 {(page - 1) * PAGE_SIZE + 1}–{Math.min(page * PAGE_SIZE, filteredDocs.length)} von {filteredDocs.length}
 </p>
 <div className="flex items-center gap-1">
 <button
 onClick={() => setPage((p) => Math.max(1, p - 1))}
 disabled={page === 1}
 className="p-1.5 rounded hover:bg-secondary text-muted-foreground disabled:opacity-40 transition-colors"
 >
 <ChevronLeft size={14} />
 </button>
 <span className="text-xs font-medium px-2">
 {page} / {totalPages}
 </span>
 <button
 onClick={() => setPage((p) => Math.min(totalPages, p + 1))}
 disabled={page === totalPages}
 className="p-1.5 rounded hover:bg-secondary text-muted-foreground disabled:opacity-40 transition-colors"
 >
 <ChevronRight size={14} />
 </button>
 </div>
 </div>
 )}
 </div>

 {/* Document detail drawer */}
 {detailDoc && (
 <DocumentDetailDrawer
 document={detailDoc}
 onClose={() => setDetailDoc(null)}
 onUpdated={(updated) => {
 setDocuments((prev) => prev.map((d) => d.id === updated.id ? updated : d))
 }}
 />
 )}

 {/* Upload dialog */}
 {showUpload && selectedProjectId && (
 <UploadDialog
 projectId={selectedProjectId}
 repositoryType="project"
 onSuccess={handleUploadSuccess}
 onClose={() => setShowUpload(false)}
 />
 )}

 {/* Delete confirm dialog */}
 {deleteConfirmId && (
 <ConfirmDialog
 message="Dieses Dokument löschen?"
 description="Das Dokument wird als gelöscht markiert und kann nicht mehr aufgerufen werden."
 confirmLabel="Löschen"
 loading={deleting}
 onConfirm={() => confirmDelete(deleteConfirmId)}
 onCancel={() => setDeleteConfirmId(null)}
 destructive
 />
 )}

 {/* Bulk delete confirm */}
 {bulkDeleteConfirm && (
 <ConfirmDialog
 message={`${selectedIds.size} Dokumente löschen?`}
 description="Die ausgewählten Dokumente werden als gelöscht markiert."
 confirmLabel="Alle löschen"
 loading={deleting}
 onConfirm={confirmBulkDelete}
 onCancel={() => setBulkDeleteConfirm(false)}
 destructive
 />
 )}
 </div>
 )
}

function ConfirmDialog({
 message,
 description,
 confirmLabel,
 loading,
 onConfirm,
 onCancel,
 destructive,
}: {
 message: string
 description: string
 confirmLabel: string
 loading: boolean
 onConfirm: () => void
 onCancel: () => void
 destructive?: boolean
}) {
 return (
 <div className="fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4">
 <div className="bg-card text-foreground rounded-xl max-w-sm w-full p-6">
 <h3 className="font-semibold text-foreground mb-2">{message}</h3>
 <p className="text-sm text-muted-foreground mb-5">{description}</p>
 <div className="flex gap-3 justify-end">
 <button
 onClick={onCancel}
 disabled={loading}
 className="text-sm px-4 py-2 rounded border border-border text-foreground hover:bg-background transition-colors"
 >
 Abbrechen
 </button>
 <button
 onClick={onConfirm}
 disabled={loading}
 className={`text-sm px-4 py-2 rounded font-medium text-white transition-colors ${
 destructive ?'bg-destructive hover:bg-destructive':'bg-primary hover:bg-primary-dark'
 } disabled:opacity-60`}
 >
 {loading ?'Bitte warten…': confirmLabel}
 </button>
 </div>
 </div>
 </div>
 )
}
