<script setup lang="ts">
import { ref, computed, onMounted, onBeforeUnmount, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { useApi } from '@/composables/useApi'
import { useFields, useViewState } from '@/composables/useFieldViews'
import { usePageLayouts } from '@/composables/usePageLayouts'
import { useSavedViews } from '@/composables/useSavedViews'
import type { SavedView } from '@/composables/useSavedViews'
import ListView from '@/components/views/ListView.vue'
import DetailView from '@/components/views/DetailViewEnhanced.vue'
import EditView from '@/components/views/EditViewEnhanced.vue'
import SavedViewPanel from '@/components/SavedViewPanel.vue'
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from '@/components/ui/dialog'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'

const route = useRoute()
const router = useRouter()
const { api } = useApi()
const { buildListViewConfig, buildDetailViewConfig, buildEditViewConfig } = useFields()
const { getDefaultPageLayout } = usePageLayouts()
const {
  savedViews,
  fetchSavedViews,
  createSavedView,
  updateSavedView,
  deleteSavedView,
  suggestViewName,
} = useSavedViews()

// Use breadcrumbs composable
const { setBreadcrumbs } = useBreadcrumbs()

// Get object API name from route (case-insensitive)
const objectApiName = computed(() => {
  const name = route.params.objectName as string
  // We'll look up the actual case-sensitive name from the backend
  return name
})
const recordId = computed(() => route.params.recordId as string)
const view = computed(() => {
  // If recordId is 'new', default to 'edit' view
  if (route.params.recordId === 'new' && !route.params.view) {
    return 'edit'
  }
  return (route.params.view as 'list' | 'detail' | 'edit') || 'list'
})

// State
const objectDefinition = ref<any>(null)
const listViewLayout = ref<any>(null)
const loading = ref(true)
const error = ref<string | null>(null)

// Use view state composable
const {
  records,
  totalCount,
  currentRecord,
  loading: dataLoading,
  saving,
  fetchRecords,
  fetchRecord,
  deleteRecord,
  deleteRecords,
  updateRecord,
  handleSave,
} = useViewState(`/runtime/objects/${objectApiName.value}/records`)

const handleAiRecordCreated = (event: Event) => {
  const detail = (event as CustomEvent).detail || {}
  if (
    detail?.objectApiName &&
    detail.objectApiName.toLowerCase() !== objectApiName.value.toLowerCase()
  ) {
    return
  }
  if (view.value === 'list') {
    initializeListRecords()
  }
}

onMounted(() => {
  window.addEventListener('ai-record-created', handleAiRecordCreated)
})

onBeforeUnmount(() => {
  window.removeEventListener('ai-record-created', handleAiRecordCreated)
})

// Compute breadcrumbs based on the current route and object data
const updateBreadcrumbs = () => {
  if (!objectDefinition.value) {
    return
  }
  
  const crumbs: Array<{ name: string; path?: string; isLast?: boolean }> = []
  
  // Add app breadcrumb if object belongs to an app
  if (objectDefinition.value?.app) {
    crumbs.push({
      name: objectDefinition.value.app.label || objectDefinition.value.app.name,
      path: undefined, // No path for app grouping
    })
  }
  
  // Add object breadcrumb - always use plural
  const objectLabel = objectDefinition.value?.pluralLabel || objectDefinition.value?.label || objectApiName.value
  
  crumbs.push({
    name: objectLabel,
    path: `/${objectApiName.value.toLowerCase()}`,
  })
  
  // Add record name if viewing/editing a specific record
  if (recordId.value && recordId.value !== 'new' && currentRecord.value) {
    const nameField = objectDefinition.value?.nameField
    let recordName = recordId.value // fallback to ID
    
    // Try to get the display name from the nameField
    if (nameField && currentRecord.value[nameField]) {
      recordName = currentRecord.value[nameField]
    }
    
    crumbs.push({
      name: recordName,
      isLast: true,
    })
  } else if (recordId.value === 'new') {
    crumbs.push({
      name: 'New',
      isLast: true,
    })
  }
  
  setBreadcrumbs(crumbs)
}

// Watch for changes that affect breadcrumbs
watch([objectDefinition, currentRecord, recordId], () => {
  updateBreadcrumbs()
}, { deep: true })

// View configs
const listConfig = computed(() => {
  if (!objectDefinition.value) return null
  // Pass the list view layout config to buildListViewConfig if available
  const layoutConfig = listViewLayout.value?.layout_config || listViewLayout.value?.layoutConfig
  return buildListViewConfig(objectDefinition.value, {
    searchable: true,
    exportable: true,
    filterable: true,
  }, layoutConfig)
})

const detailConfig = computed(() => {
  if (!objectDefinition.value) return null
  return buildDetailViewConfig(objectDefinition.value)
})

const editConfig = computed(() => {
  if (!objectDefinition.value) return null
  return buildEditViewConfig(objectDefinition.value)
})

const listPageSize = computed(() => listConfig.value?.pageSize ?? 25)
const maxFrontendRecords = computed(() => listConfig.value?.maxFrontendRecords ?? 500)
const searchQuery = ref('')
const searchSummary = ref('')
const searchLoading = ref(false)
const deleteDialogOpen = ref(false)
const deleteSubmitting = ref(false)
const pendingDeleteRows = ref<any[]>([])
const deleteSummary = ref<{ deletedIds: string[]; deniedIds: string[] } | null>(null)
const normalizeRecordId = (id: any) => String(id)

const draftEdits = ref<Record<string, Record<string, any>>>({})
const draftOriginals = ref<Record<string, Record<string, any>>>({})
const cellErrors = ref<Record<string, Record<string, string>>>({})
const savingDrafts = ref(false)

const isSearchActive = computed(() => searchQuery.value.trim().length > 0)
const pendingDeleteCount = computed(() => pendingDeleteRows.value.length)
const deniedDeleteCount = computed(() => deleteSummary.value?.deniedIds.length ?? 0)

// ── Saved views state ──────────────────────────────────────────────────────
const activeViewId = ref<string | null>(null)
const currentSearchPlan = ref<{
  strategy: string; filters: any[]; sort: any; explanation: string
} | null>(null)
const viewPanelOpen = ref(false)
const saveViewDialogOpen = ref(false)
const saveViewName = ref('')
const savingView = ref(false)

// Fetch object definition
const fetchObjectDefinition = async () => {
  try {
    loading.value = true
    error.value = null
    const response = await api.get(`/setup/objects/${objectApiName.value}`)
    objectDefinition.value = response
    
    // Fetch the default list view layout for this object
    if (response?.id) {
      try {
        listViewLayout.value = await getDefaultPageLayout(response.id, 'list')
      } catch (e) {
        // No list view layout configured, will use default behavior
        listViewLayout.value = null
      }
    }
  } catch (e: any) {
    error.value = e.message || 'Failed to load object definition'
    console.error('Error fetching object definition:', e)
  } finally {
    loading.value = false
  }
}

// Navigation handlers - use lowercase URLs
const handleRowClick = (row: any) => {
  router.push(`/${objectApiName.value.toLowerCase()}/${row.id}/detail`)
}

const handleCreate = () => {
  router.push(`/${objectApiName.value.toLowerCase()}/new`)
}

const handleEdit = (row?: any) => {
  const id = row?.id || recordId.value
  router.push(`/${objectApiName.value.toLowerCase()}/${id}/edit`)
}

const handleBack = () => {
  // Navigate to list view explicitly
  router.push(`/${objectApiName.value.toLowerCase()}/`)
}

const handleNavigate = (relatedObjectApiName: string, relatedRecordId: string) => {
  router.push(`/${relatedObjectApiName.toLowerCase()}/${relatedRecordId}/detail`)
}

const handleCreateRelated = (relatedObjectApiName: string, _parentId: string) => {
  router.push(`/${relatedObjectApiName.toLowerCase()}/new`)
}

const handleDelete = async (rows: any[]) => {
  pendingDeleteRows.value = rows
  deleteSummary.value = null
  deleteDialogOpen.value = true
}

const resetDeleteDialog = () => {
  deleteDialogOpen.value = false
  deleteSubmitting.value = false
  pendingDeleteRows.value = []
  deleteSummary.value = null
}

const confirmDelete = async () => {
  if (pendingDeleteRows.value.length === 0) {
    resetDeleteDialog()
    return
  }

  deleteSubmitting.value = true
  try {
    const ids = pendingDeleteRows.value.map(r => r.id)
    const result = await deleteRecords(ids)
    const deletedIds = result?.deletedIds ?? []
    const deniedIds = result?.deniedIds ?? []
    deleteSummary.value = { deletedIds, deniedIds }

    if (deniedIds.length === 0) {
      resetDeleteDialog()
      if (view.value !== 'list') {
        await router.push(`/${objectApiName.value.toLowerCase()}/`)
      }
    }
  } catch (e: any) {
    error.value = e.message || 'Failed to delete records'
  } finally {
    deleteSubmitting.value = false
  }
}

const handleSaveRecord = async (data: any) => {
  try {
    const savedRecord = await handleSave(data)
    if (savedRecord?.id) {
      router.push(`/${objectApiName.value.toLowerCase()}/${savedRecord.id}/detail`)
    } else {
      // Fallback to list if no ID available
      router.push(`/${objectApiName.value.toLowerCase()}/`)
    }
  } catch (e: any) {
    error.value = e.message || 'Failed to save record'
  }
}

const handleCancel = () => {
  if (recordId.value && recordId.value !== 'new') {
    router.push(`/${objectApiName.value.toLowerCase()}/${recordId.value}/detail`)
  } else {
    router.push(`/${objectApiName.value.toLowerCase()}/`)
  }
}

const loadListRecords = async (
  page = 1,
  options?: { append?: boolean; pageSize?: number }
) => {
  const pageSize = options?.pageSize ?? listPageSize.value
  const result = await fetchRecords({ page, pageSize }, { append: options?.append })
  const resolvedTotal = result?.totalCount ?? totalCount.value ?? records.value.length
  totalCount.value = resolvedTotal
  return result
}

const searchListRecords = async (
  page = 1,
  options?: { append?: boolean; pageSize?: number }
) => {
  if (!isSearchActive.value) {
    return initializeListRecords()
  }
  searchLoading.value = true
  try {
    const pageSize = options?.pageSize ?? listPageSize.value
    const response = await api.post('/ai/search', {
      objectApiName: objectApiName.value,
      query: searchQuery.value.trim(),
      page,
      pageSize,
    })
    const data = response?.data ?? []
    const total = response?.totalCount ?? data.length
    records.value = options?.append ? [...records.value, ...data] : data
    totalCount.value = total
    searchSummary.value = response?.explanation || ''

    // Capture the plan for the "Save view" feature (only when strategy is query)
    if (response?.strategy === 'query') {
      currentSearchPlan.value = {
        strategy: response.strategy,
        filters: response.filters || [],
        sort: response.sort || null,
        explanation: response.explanation || '',
      }
    } else {
      currentSearchPlan.value = null
    }

    return response
  } catch (e: any) {
    error.value = e.message || 'Failed to search records'
    return null
  } finally {
    searchLoading.value = false
  }
}

const initializeListRecords = async () => {
  const firstResult = await loadListRecords(1)
  const resolvedTotal = firstResult?.totalCount ?? totalCount.value ?? records.value.length
  const shouldPrefetchAll =
    resolvedTotal <= maxFrontendRecords.value && records.value.length < resolvedTotal

  if (shouldPrefetchAll) {
    await loadListRecords(1, { append: false, pageSize: maxFrontendRecords.value })
  }
}

const handlePageChange = async (page: number, pageSize: number) => {
  if (isSearchActive.value) {
    await searchListRecords(page, { append: page > 1, pageSize })
    return
  }
  const loadedPages = Math.ceil(records.value.length / pageSize)
  if (page > loadedPages && totalCount.value > records.value.length) {
    await loadListRecords(page, { append: true, pageSize })
  }
}

const handleLoadMore = async (page: number, pageSize: number) => {
  if (isSearchActive.value) {
    await searchListRecords(page, { append: true, pageSize })
    return
  }
  await loadListRecords(page, { append: true, pageSize })
}

const loadAllListRecords = async () => {
  if (!records.value.length) {
    await loadListRecords(1)
  }
  const resolvedTotal = totalCount.value ?? records.value.length
  if (resolvedTotal > records.value.length) {
    await loadListRecords(1, { append: false, pageSize: resolvedTotal })
  }
}

const handleViewChange = async (mode: 'list' | 'spreadsheet') => {
  if (mode === 'spreadsheet' && !isSearchActive.value) {
    await loadAllListRecords()
  }
}

const handleSearch = async (query: string) => {
  const trimmed = query.trim()
  searchQuery.value = trimmed
  if (!trimmed) {
    searchSummary.value = ''
    currentSearchPlan.value = null
    activeViewId.value = null
    await initializeListRecords()
    return
  }
  await searchListRecords(1, { append: false, pageSize: listPageSize.value })
}

const handleCellEdit = async (payload: { row: any; field: any; newValue: any; oldValue: any }) => {
  if (!payload?.row?.id || payload.newValue === payload.oldValue) return
  const recordKey = normalizeRecordId(payload.row.id)
  const fieldName = payload.field.apiName
  const originalRow = draftOriginals.value[recordKey]
  const originalValue = originalRow && Object.prototype.hasOwnProperty.call(originalRow, fieldName)
    ? originalRow[fieldName]
    : payload.oldValue

  if (Object.is(payload.newValue, originalValue)) {
    const nextDrafts = { ...draftEdits.value }
    const nextRowDrafts = { ...(nextDrafts[recordKey] || {}) }
    delete nextRowDrafts[fieldName]
    if (Object.keys(nextRowDrafts).length === 0) {
      delete nextDrafts[recordKey]
    } else {
      nextDrafts[recordKey] = nextRowDrafts
    }
    draftEdits.value = nextDrafts

    const nextOriginals = { ...draftOriginals.value }
    const nextRowOriginals = { ...(nextOriginals[recordKey] || {}) }
    delete nextRowOriginals[fieldName]
    if (Object.keys(nextRowOriginals).length === 0) {
      delete nextOriginals[recordKey]
    } else {
      nextOriginals[recordKey] = nextRowOriginals
    }
    draftOriginals.value = nextOriginals
  } else {
    draftEdits.value = {
      ...draftEdits.value,
      [recordKey]: {
        ...(draftEdits.value[recordKey] || {}),
        [fieldName]: payload.newValue,
      },
    }
    if (!originalRow || !Object.prototype.hasOwnProperty.call(originalRow, fieldName)) {
      draftOriginals.value = {
        ...draftOriginals.value,
        [recordKey]: {
          ...(draftOriginals.value[recordKey] || {}),
          [fieldName]: payload.oldValue,
        },
      }
    }
  }

  if (cellErrors.value[recordKey]?.[fieldName]) {
    const nextErrors = { ...cellErrors.value }
    const nextRowErrors = { ...(nextErrors[recordKey] || {}) }
    delete nextRowErrors[fieldName]
    if (Object.keys(nextRowErrors).length === 0) {
      delete nextErrors[recordKey]
    } else {
      nextErrors[recordKey] = nextRowErrors
    }
    cellErrors.value = nextErrors
  }
}

const handleSaveDrafts = async () => {
  if (Object.keys(draftEdits.value).length === 0) return
  savingDrafts.value = true
  const nextErrors: Record<string, Record<string, string>> = {}
  const nextDrafts = { ...draftEdits.value }
  const nextOriginals = { ...draftOriginals.value }

  for (const [recordKey, changes] of Object.entries(draftEdits.value)) {
    const record = records.value.find(item => normalizeRecordId(item.id) === recordKey)
    if (!record) {
      delete nextDrafts[recordKey]
      delete nextOriginals[recordKey]
      continue
    }
    try {
      await updateRecord(record.id, changes)
      delete nextDrafts[recordKey]
      delete nextOriginals[recordKey]
    } catch (e: any) {
      const message = e.message || 'Failed to update record'
      nextErrors[recordKey] = {}
      for (const fieldName of Object.keys(changes)) {
        nextErrors[recordKey][fieldName] = message
      }
    }
  }

  draftEdits.value = nextDrafts
  draftOriginals.value = nextOriginals
  cellErrors.value = nextErrors
  savingDrafts.value = false
  if (Object.keys(nextErrors).length > 0) {
    error.value = 'Some updates failed. Fix highlighted cells and try again.'
  }
}

const handleDiscardDrafts = () => {
  for (const [recordKey, fields] of Object.entries(draftOriginals.value)) {
    const record = records.value.find(item => normalizeRecordId(item.id) === recordKey)
    if (!record) continue
    for (const [fieldName, originalValue] of Object.entries(fields)) {
      record[fieldName] = originalValue
    }
  }
  draftEdits.value = {}
  draftOriginals.value = {}
  cellErrors.value = {}
}

// ── Saved view handlers ────────────────────────────────────────────────────

/**
 * Apply a saved view: execute its stored filters directly without re-running AI.
 */
const handleApplyView = async (view: SavedView) => {
  activeViewId.value = view.id
  searchQuery.value = ''
  searchSummary.value = view.description || ''
  currentSearchPlan.value = {
    strategy: view.strategy,
    filters: view.filters,
    sort: view.sort,
    explanation: view.description || '',
  }
  searchLoading.value = true
  try {
    const response = await api.post(
      `/runtime/objects/${objectApiName.value}/records/search`,
      {
        filters: view.filters,
        sort: view.sort,
        page: 1,
        pageSize: listPageSize.value,
      },
    )
    const data = response?.data ?? []
    records.value = data
    totalCount.value = response?.totalCount ?? data.length
  } catch (e: any) {
    error.value = e.message || 'Failed to apply saved view'
  } finally {
    searchLoading.value = false
  }
}

/**
 * Open the "Save view" dialog, pre-filling the name via AI suggestion.
 */
const handleSaveView = async () => {
  if (!currentSearchPlan.value) return
  saveViewName.value = ''
  saveViewDialogOpen.value = true
  // Async-suggest a name while dialog is open
  const objectLabel = objectDefinition.value?.label || objectApiName.value
  const suggested = await suggestViewName(
    objectLabel,
    currentSearchPlan.value.filters,
    currentSearchPlan.value.explanation,
  )
  // Only auto-fill if user hasn't typed anything yet
  if (!saveViewName.value) {
    saveViewName.value = suggested
  }
}

/**
 * Confirm the save: persist the view and close the dialog.
 */
const confirmSaveView = async () => {
  const name = saveViewName.value.trim()
  if (!name || !currentSearchPlan.value) return
  savingView.value = true
  try {
    await createSavedView({
      name,
      objectApiName: objectApiName.value,
      filters: currentSearchPlan.value.filters,
      sort: currentSearchPlan.value.sort,
      description: currentSearchPlan.value.explanation,
    })
    saveViewDialogOpen.value = false
    saveViewName.value = ''
  } catch (e: any) {
    error.value = e.message || 'Failed to save view'
  } finally {
    savingView.value = false
  }
}

const handleOpenViewManager = () => {
  viewPanelOpen.value = true
}

const handleUpdateView = async (id: string, payload: any) => {
  await updateSavedView(id, payload)
}

const handleDeleteView = async (view: SavedView) => {
  await deleteSavedView(view.id)
  if (activeViewId.value === view.id) {
    activeViewId.value = null
    currentSearchPlan.value = null
    await initializeListRecords()
  }
}

watch(
  () => records.value.map(record => normalizeRecordId(record.id)),
  (ids) => {
    const idSet = new Set(ids)
    const nextDrafts: Record<string, Record<string, any>> = {}
    const nextOriginals: Record<string, Record<string, any>> = {}
    const nextErrors: Record<string, Record<string, string>> = {}

    for (const [recordKey, fields] of Object.entries(draftEdits.value)) {
      if (idSet.has(recordKey)) nextDrafts[recordKey] = fields
    }
    for (const [recordKey, fields] of Object.entries(draftOriginals.value)) {
      if (idSet.has(recordKey)) nextOriginals[recordKey] = fields
    }
    for (const [recordKey, fields] of Object.entries(cellErrors.value)) {
      if (idSet.has(recordKey)) nextErrors[recordKey] = fields
    }

    draftEdits.value = nextDrafts
    draftOriginals.value = nextOriginals
    cellErrors.value = nextErrors
  }
)

// Watch for route changes
watch(() => route.params, async (newParams, oldParams) => {
  // Reset current record when navigating to 'new'
  if (newParams.recordId === 'new') {
    currentRecord.value = null
  }
  
  // Fetch record if navigating to existing record
  if (newParams.recordId && newParams.recordId !== 'new' && newParams.recordId !== oldParams.recordId) {
    await fetchRecord(newParams.recordId as string)
  }
  
  // Fetch records if navigating back to list
  if (!newParams.recordId && !newParams.view) {
    await initializeListRecords()
  }
}, { deep: true })

// Initialize
onMounted(async () => {
  await fetchObjectDefinition()
  
  if (view.value === 'list') {
    await initializeListRecords()
    // Load saved views for this object
    fetchSavedViews(objectApiName.value).catch(() => {})
  } else if (recordId.value && recordId.value !== 'new') {
    await fetchRecord(recordId.value)
  }
  
  // Update breadcrumbs after data is loaded
  updateBreadcrumbs()
})
</script>

<template>
  <NuxtLayout name="default">
    <div class="object-view-container">
      
      <!-- Page Header -->
      <div v-if="!loading && !error && view === 'list'" class="mb-6">
        <h1 class="text-3xl font-bold">{{ objectDefinition?.label || objectApiName }}</h1>
        <p v-if="objectDefinition?.description" class="text-muted-foreground mt-2">
          {{ objectDefinition.description }}
        </p>
      </div>

      <!-- Loading State -->
      <div v-if="loading" class="flex items-center justify-center min-h-screen">
        <div class="text-center space-y-4">
          <div class="animate-spin rounded-full h-12 w-12 border-b-2 border-primary mx-auto"></div>
          <p class="text-muted-foreground">Loading {{ objectApiName }}...</p>
        </div>
      </div>

      <!-- Error State -->
      <div v-else-if="error" class="flex items-center justify-center min-h-screen">
        <div class="text-center space-y-4 max-w-md">
          <div class="text-destructive text-5xl">⚠️</div>
          <h2 class="text-2xl font-bold">Error</h2>
          <p class="text-muted-foreground">{{ error }}</p>
          <Button @click="router.back()">Go Back</Button>
        </div>
      </div>

      <!-- List View -->
      <ListView
        v-else-if="view === 'list' && listConfig"
        :config="listConfig"
        :data="records"
        :loading="dataLoading || searchLoading"
        :total-count="totalCount"
        :search-summary="searchSummary"
        :base-url="`/runtime/objects`"
        :draft-edits="draftEdits"
        :cell-errors="cellErrors"
        :saving-drafts="savingDrafts"
        :saved-views="savedViews"
        :active-view-id="activeViewId"
        :current-search-plan="currentSearchPlan"
        :saving-view="savingView"
        selectable
        @row-click="handleRowClick"
        @create="handleCreate"
        @edit="handleEdit"
        @delete="handleDelete"
        @search="handleSearch"
        @page-change="handlePageChange"
        @load-more="handleLoadMore"
        @view-change="handleViewChange"
        @cell-edit="handleCellEdit"
        @save-drafts="handleSaveDrafts"
        @discard-drafts="handleDiscardDrafts"
        @apply-view="handleApplyView"
        @save-view="handleSaveView"
        @open-view-manager="handleOpenViewManager"
      />

      <!-- Detail View -->
      <DetailView
        v-else-if="view === 'detail' && detailConfig && currentRecord"
        :config="detailConfig"
        :data="currentRecord"
        :loading="dataLoading"
        :object-id="objectDefinition?.id"
        :base-url="`/runtime/objects`"
        @edit="handleEdit"
        @delete="() => handleDelete([currentRecord])"
        @back="handleBack"
        @navigate="handleNavigate"
        @create-related="handleCreateRelated"
      />

      <!-- Edit View -->
      <EditView
        v-else-if="(view === 'edit' || recordId === 'new') && editConfig"
        :config="editConfig"
        :data="currentRecord || {}"
        :loading="dataLoading"
        :saving="saving"
        :object-id="objectDefinition?.id"
        :base-url="`/runtime/objects`"
        @save="handleSaveRecord"
        @cancel="handleCancel"
        @back="handleBack"
      />
    </div>

    <Dialog v-model:open="deleteDialogOpen">
      <DialogContent class="sm:max-w-[520px]">
        <DialogHeader>
          <DialogTitle>Delete records</DialogTitle>
          <DialogDescription>
            This action cannot be undone.
          </DialogDescription>
        </DialogHeader>

        <div class="space-y-2 text-sm">
          <p>
            You are about to delete {{ pendingDeleteCount }} record<span v-if="pendingDeleteCount !== 1">s</span>.
          </p>
          <p v-if="deleteSummary" class="text-muted-foreground">
            Deleted {{ deleteSummary.deletedIds.length }} record<span v-if="deleteSummary.deletedIds.length !== 1">s</span>.
          </p>
          <p v-if="deniedDeleteCount > 0" class="text-destructive">
            {{ deniedDeleteCount }} record<span v-if="deniedDeleteCount !== 1">s</span> could not be deleted due to missing permissions.
          </p>
          <p v-if="!deleteSummary" class="text-muted-foreground">
            Records you do not have permission to delete will be skipped.
          </p>
        </div>

        <DialogFooter>
          <Button variant="outline" @click="resetDeleteDialog" :disabled="deleteSubmitting">
            {{ deleteSummary ? 'Close' : 'Cancel' }}
          </Button>
          <Button
            v-if="!deleteSummary"
            variant="destructive"
            @click="confirmDelete"
            :disabled="deleteSubmitting"
          >
            Delete
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>

    <!-- Save view dialog -->
    <Dialog v-model:open="saveViewDialogOpen">
      <DialogContent class="sm:max-w-[420px]">
        <DialogHeader>
          <DialogTitle>Save view</DialogTitle>
          <DialogDescription>
            Give this search a name so you can reuse it later.
          </DialogDescription>
        </DialogHeader>
        <div class="space-y-2 py-2">
          <Label for="view-name">View name</Label>
          <Input
            id="view-name"
            v-model="saveViewName"
            placeholder="e.g. Cocker Spaniels"
            @keyup.enter="confirmSaveView"
          />
        </div>
        <DialogFooter>
          <Button variant="outline" @click="saveViewDialogOpen = false" :disabled="savingView">
            Cancel
          </Button>
          <Button @click="confirmSaveView" :disabled="savingView || !saveViewName.trim()">
            Save
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>

    <!-- Saved views slide-over panel -->
    <SavedViewPanel
      v-model:open="viewPanelOpen"
      :views="savedViews"
      :object-label="objectDefinition?.pluralLabel || objectDefinition?.label || objectApiName"
      :active-view-id="activeViewId"
      @apply-view="handleApplyView"
      @update-view="handleUpdateView"
      @delete-view="handleDeleteView"
    />
  </NuxtLayout>
</template>

<style scoped>
.object-view-container {
  padding: 2rem;
}
</style>
