<script setup lang="ts">
import { computed, defineComponent, h, nextTick, onBeforeUnmount, onMounted, PropType, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { AgGridVue } from 'ag-grid-vue3'
import type {
  CellValueChangedEvent,
  ColDef,
  FirstDataRenderedEvent,
  GridApi,
  GridReadyEvent,
  ICellRendererParams,
  IGroupCellRendererParams,
  IRowNode,
  ValueFormatterParams
} from 'ag-grid-community'
import { AG_GRID_LOCALE_CN } from '@ag-grid-community/locale'
import {
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogOverlay,
  AlertDialogPortal,
  AlertDialogRoot,
  AlertDialogTitle
} from 'reka-ui'
import { Button } from '@/components/ui/button'
import { agGridDefaultColDef, myTheme, agGridStyle } from '@/lib/diyAgGridOptions'
import { withReadonlyAutoHeight } from '@/lib/agGridReadonlyAutoHeight'
import { getServiceDictItemById, getWorkListEntries, wholeProcessTasks } from '@/sql'
import { WorkType } from '@/sql'
import { useZxFwPricingStore } from '@/pinia/zxFwPricing'
import { useKvStore } from '@/pinia/kv'
import { useDataStore } from '@/pinia/zx'
import { Trash2 } from 'lucide-vue-next'

interface WorkContentRow {
  id: string
  content: string
  type: WorkType
  dictOrder?: number
  serviceGroup?: string
  serviceid?: number | null
  remark: string
  checked: boolean
  custom: boolean
  isAddTrigger?: boolean
  path: string[]
}

interface WorkContentState {
  detailRows: WorkContentRow[]
}

// dictMode: 'service' 按serviceId筛选workList；'additional' 取serviceid=-1的数据；'none' 不加载词典
const props = withDefaults(defineProps<{
  title?: string
  storageKey: string
  serviceId?: number | string
  contractId?: string
  projectInfoKey?: string
  dictMode?: 'service' | 'additional' | 'none'
}>(), {
  title: '',
  projectInfoKey: 'xm-base-info-v1',
  dictMode: 'none'
})

const emit = defineEmits<{
  checkedChange: [value: string[]]
}>()
const { t, locale } = useI18n()

const zxFwPricingStore = useZxFwPricingStore()
const kvStore = useKvStore()
const gridApi = ref<GridApi<WorkContentRow> | null>(null)
const rowData = ref<WorkContentRow[]>([])
const isWholeProcessGroupedMode = ref(false)
const groupedServiceGroups = ref<string[]>([])
const defaultColDef = {
  ...(agGridDefaultColDef as ColDef<WorkContentRow>),
  resizable: true,
  sortable: false,
  filter: false
}

const syncGroupedRowsRender = async () => {
  await nextTick()
  const api = gridApi.value
  if (!api || api.isDestroyed?.()) return
  if (isWholeProcessGroupedMode.value) {
    api.expandAll()
  }
  api.refreshClientSideRowModel('group')
  api.refreshCells({ force: true })
  api.redrawRows()
  setTimeout(() => {
    const liveApi = gridApi.value
    if (!liveApi || liveApi.isDestroyed?.()) return
    if (isWholeProcessGroupedMode.value) {
      liveApi.expandAll()
    }
    liveApi.refreshCells({ force: true })
    liveApi.redrawRows()
  }, 16)
}

const toServiceId = (value: unknown): number | null => {
  const parsed = Number(value)
  if (!Number.isSafeInteger(parsed)) return null
  return parsed
}

const getStableDictRowKeyFromId = (idRaw: unknown) => {
  const id = String(idRaw || '').trim()
  if (!id.startsWith('dict-')) return ''
  const matched = /^dict-(-?\d+)-(\d+)(?:-|$)/.exec(id)
  if (!matched) return ''
  return `sid:${matched[1]}|order:${matched[2]}`
}

const getDictRowMergeKey = (row: Pick<WorkContentRow, 'id' | 'dictOrder' | 'content' | 'serviceid' | 'serviceGroup'>) => {
  const fromId = getStableDictRowKeyFromId(row.id)
  if (fromId) return fromId
  const content = String(row.content || '').trim()
  const serviceid = toServiceId(row.serviceid)
  const dictOrder = Number(row.dictOrder)
  if (serviceid != null && Number.isFinite(dictOrder)) return `sid:${serviceid}|order:${dictOrder}`
  if (serviceid != null) return `sid:${serviceid}|content:${content}`
  const groupName = String(row.serviceGroup || '').trim()
  if (groupName) return `group:${groupName}|content:${content}`
  return `content:${content}`
}



const loadProjectIndustryId = async () => {
  try {
    const baseInfo = await kvStore.getItem<{ projectIndustry?: unknown }>(props.projectInfoKey)
    const raw = typeof baseInfo?.projectIndustry === 'string' ? baseInfo.projectIndustry.trim() : ''
    if (raw.toUpperCase() === 'E2') return 0
    if (raw.toUpperCase() === 'E3') return 1
    if (raw.toUpperCase() === 'E4') return 2
    const n = Number(raw)
    return Number.isFinite(n) ? n : null
  } catch (_error) {
    return null
  }
}

const buildDefaultRowsFromDict = async (): Promise<WorkContentRow[]> => {
  const rows: WorkContentRow[] = []
  const contentRows = await useDataStore().query([
    { field: 'type', value: `${props.contractId}-content`, operator: 'eq' }
  ])
  let contentArray = [];
  if (contentRows.length > 0) {
    contentArray = contentRows[0].value;
  }
  const entries = getWorkListEntries(locale.value) as Array<{
    text: string
    serviceid: number
    order: number
    type: number
    code: string
    leaf?: boolean
    textEn?: string
    checked: boolean
    custom: boolean
    remark: string
  }>;

  // 根据 code 将 contentArray 里存在的数据替换到 entries 中
  const contentMap = new Map<string, string>()
  if (Array.isArray(contentArray)) {
    for (const item of contentArray) {
      if (item?.code != null) {
        contentMap.set(`${item.code}-${item.content}`, item)
      }
    }
  }
  for (let entry of entries) {
    const item = contentMap.get(`${entry.code}-${entry.text}`)
    if (item != null && `${entry.code}-${entry.text}` == `${item.code}-${item.content}`) {
      entry.checked = item.checked
      entry.custom = item.custom
      entry.remark = item.remark
    }
  }

  // 过滤数据
  let filtered = [...entries]

  // 按 order 排序
  filtered.sort((a, b) => a.order - b.order)

  // 构建 code -> 父节点信息的映射
  const parentMap = new Map<string, { serviceGroup: string; content: string }>()

  // 第一次遍历：收集所有 leaf: false 的父节点
  let i = 1;
  for (const entry of filtered) {
    if (entry.leaf === false) {
      /*const serviceItem = getServiceDictItemById(entry.serviceid) as { code?: string; name?: string } | undefined
      const serviceGroup = serviceItem
          ? `${String(serviceItem.code || '').trim()} ${String(serviceItem.name || '').trim()}`.trim()
          : entry.code*/

      parentMap.set(entry.code, {
        serviceGroup: `${entry.text}`,
        content: String(entry.text || '').trim()
      })
      i++;
    }
  }
  // 第二次遍历：处理 leaf: true 的子节点
  for (const entry of filtered) {
    // 只处理 leaf: true 的节点（子节点）
    if (entry.leaf !== true) {
      continue
    }

    const content = String(entry.text || '').trim()
    if (!content) continue

    const typeLabel = ((): WorkType => {
      if (entry.type === 1) return t('workContent.type.optional') as WorkType
      if (entry.type === 2) return t('workContent.type.daily') as WorkType
      if (entry.type === 3) return t('workContent.type.special') as WorkType
      if (entry.type === 4) return t('workContent.type.additional') as WorkType
      return t('workContent.type.basic') as WorkType
    })()

    /*const serviceItem = getServiceDictItemById(entry.serviceid) as { code?: string; name?: string } | undefined
    const serviceGroup = serviceItem
        ? `${String(serviceItem.code || '').trim()} ${String(serviceItem.name || '').trim()}`.trim()
        : entry.code*/

    // 查找父节点
    const parent = parentMap.get(entry.code)
    const parentName = parent?.serviceGroup

    // 构建 path: [父节点名称, 子节点内容]
    const path = [parentName, content]

    rows.push({
      id: `dict-${entry.serviceid}-${entry.code}-${entry.order}` ||
          `dict-${entry.serviceid}-${entry.content.substring(0, 8)}-${entry.order}`,
      code: entry.code,
      content,
      type: typeLabel,
      dictOrder: entry.order,
      serviceGroup: parentName, // 保留 serviceGroup 用于显示
      serviceid: toServiceId(entry.serviceid),
      remark: entry.remark == null ? '' : entry.remark,
      checked: entry.checked == null ? true : entry.checked,
      custom: entry.custom == null ? false : entry.custom,
      leaf: entry.leaf,
      path // 使用 [父节点, 子节点] 的路径结构
    })
  }

  return rows
}

const buildDefaultRowsFromDict2 = async (): Promise<WorkContentRow[]> => {
  const rows: WorkContentRow[] = []
  const entries = getWorkListEntries(locale.value) as Array<{ text: string; serviceid: number; order: number; type: number }>
  const filtered = [...entries]
  /*let filtered: typeof entries = []
  let groupedServiceIds: number[] = []
  let groupedBy: 'fid' | 'sid' | null = null
  let matchedWholeProcessGroup: { fid: number; industry: number; sid: number[] } | null = null
  isWholeProcessGroupedMode.value = false
  groupedServiceGroups.value = []
  if (props.dictMode === 'service') {
    const sid = Number(props.serviceId.split('-').pop())
    const industryId = await loadProjectIndustryId()
    const wholeProcessGroupByFid = wholeProcessTasks.find(
      item => Number(item.fid) === sid && Number(item.industry) === industryId
    )

    const wholeProcessGroup = wholeProcessGroupByFid 
    groupedBy = wholeProcessGroupByFid ? 'fid' :  null
    if (wholeProcessGroup) {
      groupedServiceIds = Array.isArray(wholeProcessGroup.sid)
        ? wholeProcessGroup.sid.map(id => Number(id)).filter(Number.isFinite)
        : []
      matchedWholeProcessGroup = {
        fid: Number(wholeProcessGroup.fid),
        industry: Number(wholeProcessGroup.industry),
        sid: [...groupedServiceIds]
      }
      const groupedSet = new Set(groupedServiceIds)
      filtered = entries.filter(e => groupedSet.has(Number(e.serviceid)))
      isWholeProcessGroupedMode.value = groupedServiceIds.length > 0
      groupedServiceGroups.value = groupedServiceIds.map(sid => {
        const serviceItem = getServiceDictItemById(sid) as { code?: string; name?: string } | undefined
        return serviceItem
          ? `${String(serviceItem.code || '').trim()} ${String(serviceItem.name || '').trim()}`.trim()
          : String(sid)
      })
    } else {
      filtered = entries.filter(e => e.serviceid === sid)
    }

  } else if (props.dictMode === 'additional') {
    filtered = entries.filter(e => e.serviceid === -1 && props.storageKey.split('-').at(-1) =='2')
  } else {
    return []
  }

  if (isWholeProcessGroupedMode.value) {
    const sidIndex = new Map(groupedServiceIds.map((sid, index) => [sid, index]))
    filtered.sort((a, b) => {
      const indexA = sidIndex.get(Number(a.serviceid)) ?? Number.MAX_SAFE_INTEGER
      const indexB = sidIndex.get(Number(b.serviceid)) ?? Number.MAX_SAFE_INTEGER
      if (indexA !== indexB) return indexA - indexB
      return a.order - b.order
    })
  } else {
    filtered.sort((a, b) => a.order - b.order)
  }*/

  for (const entry of filtered) {
    const content = String(entry.text || '').trim()
    if (!content) continue
    const typeLabel = ((): WorkType => {
      if (entry.type === 1) return t('workContent.type.optional') as WorkType
      if (entry.type === 2) return t('workContent.type.daily') as WorkType
      if (entry.type === 3) return t('workContent.type.special') as WorkType
      if (entry.type === 4) return t('workContent.type.additional') as WorkType
      return t('workContent.type.basic') as WorkType
    })()
    const serviceItem = getServiceDictItemById(entry.serviceid) as { code?: string; name?: string } | undefined
    const serviceGroup = serviceItem
      ? `${String(serviceItem.code || '').trim()} ${String(serviceItem.name || '').trim()}`.trim()
      : ''
    rows.push({
      id: `dict-${entry.serviceid}-${entry.order}`,
      content,
      type: typeLabel,
      dictOrder: entry.order,
      serviceGroup,
      serviceid: toServiceId(entry.serviceid),
      remark: '',
      checked: true,
      custom: false,
      path: isWholeProcessGroupedMode.value && serviceGroup
        ? [serviceGroup, content]
        : [typeLabel, content]
    })
  }
  return rows
}
const deleteConfirmOpen = ref(false)
const pendingDeleteRowId = ref<string | null>(null)
const pendingDeleteRowName = ref('')
const requestDeleteRow = (id: string, name?: string) => {
  pendingDeleteRowId.value = id
  pendingDeleteRowName.value = String(name || '').trim() || t('workContent.currentRow')
  deleteConfirmOpen.value = true
}
const checkedIds = computed(() =>
  rowData.value.filter(item => !isAddTriggerRow(item) && item.checked).map(item => item.id)
)

// 导出用：自定义内容全部包含，默认词典内容只含勾选的
const selectedTexts = computed(() =>
  rowData.value
    .filter(item => !isAddTriggerRow(item) && (item.custom || item.checked))
    .map(item => item.content)
    .filter(Boolean)
)

defineExpose({ selectedTexts })

const emitCheckedChange = () => {
  emit('checkedChange', [...checkedIds.value])
}

const saveToStore = async () => {
  /*const payload: WorkContentState = {
    detailRows: getPersistableRows(rowData.value).map(item => ({ ...item }))
  }
  zxFwPricingStore.setKeyState(props.storageKey, payload)
  emitCheckedChange()*/
  const rows = { value: [...rowData.value], type: `${props.contractId}-content`, id: `${props.contractId}-content` }
  const stats = await useDataStore().upsert(rows)
  console.log('💾 数据保存成功:', rows)
}

const loadFromStore = async () => {
  // TODO 数据重新加载
  let defaultRows = await buildDefaultRowsFromDict()
  const zxRows = await useDataStore().query([
    { field: 'type', value: `${props.contractId}-zxFw`, operator: 'eq' }
  ])
  const zxRowCodes = [
    ...new Set(
        zxRows
            .map(row => row.code)
            .filter(Boolean)
            .flatMap(code => {
              const mapping = {
                'D1': ['D3-1', 'D3-2', 'D3-3', 'D3-4', 'D3-6-1', 'D3-7', 'D4-6', 'D5-1'],
                'D2-1': ['D3-1', 'D3-2', 'D3-3'],
                'D2-2': ['D3-4', 'D3-5', 'D3-6'],
                'D3-1': ['D3-1'],
                'D3-2': ['D3-2'],
                'D3-3': ['D3-3'],
                'D3-4': ['D3-4'],
                'D3-6-1': ['D3-6-1'],
                'D3-7': ['D3-7'],
                'D4-6': ['D4-6'],
                'D5-1': ['D5-1']
              }
              return mapping[code] || []
            })
    ),
    'D0-1',
    'D0'
  ]

  // 过滤 defaultRows，只保留 code 在 zxRowCodes 中的行
  rowData.value = defaultRows.filter(row =>
      row.code && zxRowCodes.includes(row.code)
  )


  /*const contentRows = await useDataStore().query([
    { field: 'type', value: `${props.contractId}-content`, operator: 'eq' }
  ])
  if (contentRows.length > 0) {
    rowData.value = contentRows[0].value;
  } else {

  }*/
  /*console.log(rowData.value)
  console.log('zxRowCodes', zxRowCodes)*/

  /*const state = await zxFwPricingStore.loadKeyState<WorkContentState>(props.storageKey)
  if (Array.isArray(state?.detailRows) && state.detailRows.length > 0) {
    const persistedRows = state.detailRows.map(item => ({
      ...item,
      type: item.custom ? t('workContent.type.custom') : (item.type || t('workContent.type.basic')),
      checked: item.custom ? false : item.checked !== false,
      serviceid: toServiceId(item.serviceid),
      path: Array.isArray(item.path) && item.path.length ? item.path : [t('workContent.type.custom'), item.content || t('workContent.unnamed')]
    })) as WorkContentRow[]

    const defaultGroupServiceIdMap = new Map<string, number>()
    for (const row of defaultRows) {
      const groupName = String(row.serviceGroup || '').trim()
      const serviceid = toServiceId(row.serviceid)
      if (!groupName || serviceid == null) continue
      defaultGroupServiceIdMap.set(groupName, serviceid)
    }
    for (const row of persistedRows) {
      if (row.serviceid != null) continue
      const groupName = String(row.serviceGroup || '').trim()
      if (!groupName) continue
      const fallbackServiceId = defaultGroupServiceIdMap.get(groupName)
      if (fallbackServiceId != null) {
        row.serviceid = fallbackServiceId
      }
    }

    // 按最新词典规则重建默认行，再合并历史勾选/备注，保证分组规则变更后立即生效。
    if (defaultRows.length > 0) {
      const persistedCustomRows = persistedRows.filter(item => item.custom)
      const persistedDictRows = persistedRows.filter(item => !item.custom)
      const persistedByKey = new Map(
        persistedDictRows.map(item => [getDictRowMergeKey(item), item])
      )
      const mergedDictRows = defaultRows.map(item => {
        const key = getDictRowMergeKey(item)
        const old = persistedByKey.get(key)
        if (!old) return item
        return {
          ...item,
          checked: old.checked !== false,
          remark: String(old.remark || '')
        }
      })
      rowData.value = withAddTriggerRows([...mergedDictRows, ...persistedCustomRows])
      saveToStore()
    } else {
      rowData.value = withAddTriggerRows(persistedRows)
      isWholeProcessGroupedMode.value = rowData.value.some(
        item => !item.custom && Boolean(String(item.serviceGroup || '').trim())
      )
    }
  } else {
    rowData.value = withAddTriggerRows(defaultRows)
    saveToStore()
  }*/
  // emitCheckedChange()
  // await syncGroupedRowsRender()
}

const handleCheckedToggle = (id: string, checked: boolean) => {
  const target = rowData.value.find(item => item.id === id)
  if (!target || isAddTriggerRow(target)) return
  target.checked = checked
  gridApi.value?.refreshCells({ force: true })
  gridApi.value?.redrawRows()
  saveToStore()
}

const getGroupCheckableRows = (node?: IRowNode<WorkContentRow> | null) => {
  if (!node) return []
  return (node.allLeafChildren || [])
    .map(item => item.data)
    .filter((item): item is WorkContentRow => Boolean(item && !isAddTriggerRow(item) && !item.custom))
}

const handleGroupCheckedToggle = (node: IRowNode<WorkContentRow>, checked: boolean) => {
  const groupRows = getGroupCheckableRows(node)
  if (groupRows.length === 0) return
  const targetIds = new Set(groupRows.map(item => item.id))
  let changed = false
  for (const row of rowData.value) {
    if (!targetIds.has(row.id)) continue
    if (row.checked === checked) continue
    row.checked = checked
    changed = true
  }
  if (!changed) return
  gridApi.value?.refreshCells({ force: true })
  gridApi.value?.redrawRows()
  saveToStore()
}

const groupRowRendererParams = computed<IGroupCellRendererParams<WorkContentRow> | undefined>(() => {
  if (!isWholeProcessGroupedMode.value) return undefined
  return {
    suppressCount: true,
    innerRenderer: (params: ICellRendererParams<WorkContentRow>) => {
      const wrapper = document.createElement('div')
      wrapper.className = 'work-content-group-row'
      // 只渲染标签，不渲染复选框
      const label = document.createElement('span')
      label.className = 'work-content-group-label'
      label.textContent = String(params.valueFormatted || params.value || params.node.key || '')
      wrapper.appendChild(label)
      return wrapper
    }
  }
})

const contentCellRenderer = (params: ICellRendererParams<WorkContentRow>) => {
  const data = params.data
  if (!data) return ''
  const wrapper = document.createElement('div')
  wrapper.style.display = 'flex'
  wrapper.style.alignItems = 'center'
  wrapper.style.justifyContent = 'space-between'
  wrapper.style.gap = '6px'
  wrapper.style.width = '100%'
  wrapper.className = 'work-content-cell'
  if (isAddTriggerRow(data)) {
    const label = document.createElement('span')
    label.className = 'work-content-placeholder'
    label.textContent = String(data.content || t('workContent.addCustom'))
    wrapper.appendChild(label)
    return wrapper
  }

  if (!isAddTriggerRow(data) && !data.custom) {
    const checkbox = document.createElement('input')
    checkbox.type = 'checkbox'
    checkbox.checked = data.checked
    checkbox.className = 'work-content-check'
    checkbox.addEventListener('change', (event: Event) => {
      const target = event.target as HTMLInputElement
      handleCheckedToggle(data.id, target.checked)
    })
    wrapper.appendChild(checkbox)
  }

  const label = document.createElement('span')
  if (!data.content) {
    label.className = 'work-content-placeholder'
    label.textContent = t('workContent.clickToInputContent')
  } else {
    label.className = 'work-content-text'
    label.textContent = data.content
  }
  wrapper.appendChild(label)
  return wrapper
}

const columnDefs: ColDef<WorkContentRow>[] = [
  {
    headerName: t('workContent.columns.no'),
    minWidth: 60,
    width: 70,
    suppressMovable: true,
    editable: false,
    colSpan: params => (isAddTriggerRow(params.data) ? 5 : 1),
    /*valueGetter: params => {
      if (!params.node || params.node.group || isAddTriggerRow(params.data)) return ''
      if (!isWholeProcessGroupedMode.value) return (params.node.rowIndex ?? 0) + 1
      const siblings = params.node.parent?.childrenAfterSort || []
      const visibleLeafSiblings = siblings.filter(node => !node.group && !isAddTriggerRow(node.data as WorkContentRow))
      const index = visibleLeafSiblings.findIndex(node => node.id === params.node?.id)
      return index >= 0 ? index + 1 : ''
    },*/
    valueGetter: params => {
      // 1. 添加触发行不显示序号
      if (isAddTriggerRow(params.data)) return ''

      // 2. 分组行（一级标题）处理
      if (params.node.group) {
        // 获取当前分组在所有分组中的索引
        const allGroups = params.api.getRowNode(params.node.id)?.allChildren
            ?.filter(node => node.group && !isAddTriggerRow(node.data))
        const groupIndex = allGroups?.indexOf(params.node) + 1 || 1
        return String(groupIndex)
      }

      // 3. 二级节点处理（叶子节点）
      const parentNode = params.node.parent
      if (!parentNode) return ''

      // 获取父分组的序号
      const parentGroupIndex = parentNode.allChildren
          ?.filter(node => node.group && !isAddTriggerRow(node.data))
          .indexOf(parentNode) + 1 || 1

      // 获取当前节点在分组内的序号
      const siblings = parentNode.childrenAfterSort || []
      const visibleLeafSiblings = siblings.filter(node =>
          !node.group && !isAddTriggerRow(node.data as WorkContentRow)
      )
      const childIndex = visibleLeafSiblings.findIndex(node => node.id === params.node?.id) + 1

      return `${childIndex}`
      // return `${parentGroupIndex}.${childIndex}`
    },
    cellRenderer: (params: ICellRendererParams<WorkContentRow>) => {
      const row = params.data
      if (!isAddTriggerRow(row)) return params.value
      const button = document.createElement('button')
      button.type = 'button'
      button.className =
        'inline-flex h-full w-full cursor-pointer items-center justify-center rounded-none border-0 bg-transparent px-3 py-3 text-sm font-medium text-blue-700 hover:bg-transparent focus:outline-none'
      button.textContent = `＋ ${t('workContent.addCustom')}`
      button.addEventListener('click', event => {
        event.preventDefault()
        event.stopPropagation()
        addCustomRow(String(row?.serviceGroup || '').trim())
      })
      return button
    }
  },
  {
    headerName: t('workContent.columns.content'),
    field: 'content',
    minWidth: 320,
    flex: 2,
    cellClass: 'work-content-main-cell',
    editable: params => Boolean(params.data?.custom && !isAddTriggerRow(params.data)),
 
    valueParser: params => String(params.newValue || '').trim(),
    wrapText: true,
    autoHeight: true,

    cellStyle: { whiteSpace: 'normal', lineHeight: '1.5' },
    cellRenderer: contentCellRenderer
  },
  /*{
    headerName: t('workContent.columns.type'),
    field: 'type',
    minWidth: 100,
    width: 120,
    editable: false,
    valueFormatter: (params: ValueFormatterParams<WorkContentRow>) =>
      isAddTriggerRow(params.data) ? '' : String(params.value || '')
  },*/
  {
    headerName: t('workContent.columns.remark'),
    field: 'remark',
    minWidth: 180,
    flex: 1.2,
    editable: params => !isAddTriggerRow(params.data),
    cellEditor: 'agLargeTextCellEditor',
    wrapText: true,
    autoHeight: true,
    cellStyle: { whiteSpace: 'normal', lineHeight: '1.4' },
    cellClass: 'remark-wrap-cell',
    cellClassRules: {
      'editable-cell-empty': params => params.value == null || params.value === ''
    },
    valueFormatter: params => (isAddTriggerRow(params.data) ? '' : (params.value || t('workContent.clickToInput')))
  },
  /*{
    headerName: t('workContent.columns.actions'),
    colId: 'actions',
    minWidth: 92,
    maxWidth: 110,
    flex: 0.8,
    editable: false,
    sortable: false,
    filter: false,
    suppressMovable: true,
    cellRenderer: defineComponent({
      name: 'HtFeeGridActionCellRenderer',
      props: {
        params: {
          type: Object as PropType<ICellRendererParams<WorkContentRow>>,
          required: true
        }
      },
      setup(rendererProps) {
        return () => {
          const row = rendererProps.params.data
          if (!row?.custom) return null
          const onDelete = (event: MouseEvent) => {
            event.preventDefault()
            event.stopPropagation()
            requestDeleteRow(row.id, row.content)
          }
          return h(
            'button',
            {
              type: 'button',
              class:
                'inline-flex cursor-pointer items-center gap-1 rounded border border-red-200 px-2 py-1 text-xs text-red-600 hover:bg-red-50',
              onClick: onDelete
            },
            [h(Trash2, { size: 12, 'aria-hidden': 'true' }), h('span', t('common.delete'))]
          )
        }
      }
    })
  }*/
]
const gridColumnDefs = computed(() => withReadonlyAutoHeight(columnDefs))

const isAddTriggerRow = (row?: WorkContentRow | null) => Boolean(row?.isAddTrigger)
const getPersistableRows = (rows: WorkContentRow[]) => rows.filter(item => !isAddTriggerRow(item))

const createAddTriggerRow = (groupName?: string): WorkContentRow => {
  const suffix = groupName ? String(groupName).trim() : 'root'
  return {
    id: `add-trigger-${suffix}`,
    content: t('workContent.addCustom'),
    type: t('workContent.type.custom') as WorkType,
    serviceGroup: groupName || '',
    serviceid: null,
    remark: '',
    checked: false,
    custom: false,
    isAddTrigger: true,
    path: groupName ? [groupName, '__add__'] : ['__add__']
  }
}

const withAddTriggerRows2 = (rows: WorkContentRow[]) => {
  const pureRows = getPersistableRows(rows)
  if (isWholeProcessGroupedMode.value) {
    const groupedMap = new Map<string, WorkContentRow[]>()
    for (const row of pureRows) {
      const groupName = String(row.serviceGroup || '').trim() || t('workContent.ungrouped')
      if (!groupedMap.has(groupName)) groupedMap.set(groupName, [])
      groupedMap.get(groupName)?.push(row)
    }
    const groupOrder = groupedServiceGroups.value.length
        ? [...groupedServiceGroups.value]
        : [...groupedMap.keys()]
    const result: WorkContentRow[] = []
    const used = new Set<string>()
    for (const groupName of groupOrder) {
      used.add(groupName)
      result.push(...(groupedMap.get(groupName) || []))
      result.push(createAddTriggerRow(groupName))
    }
    for (const [groupName, groupRows] of groupedMap.entries()) {
      if (used.has(groupName)) continue
      result.push(...groupRows)
      result.push(createAddTriggerRow(groupName))
    }
    return result
  }
  return [...pureRows, createAddTriggerRow()]
}

const withAddTriggerRows = (rows: WorkContentRow[]) => {
  const pureRows = getPersistableRows(rows)
  return pureRows
}

const getDataPath = (data: WorkContentRow) => {
  const path = Array.isArray(data?.path)
    ? data.path.map(segment => String(segment || '').trim()).filter(Boolean)
    : []
  if (path.length > 0) return path
  const fallback = String(data?.id || '').trim()
  return [fallback || '__row__']
}

const addCustomRow = (groupName?: string) => {
  const ts = Date.now()
  const finalGroupName = isWholeProcessGroupedMode.value
    ? String(groupName || groupedServiceGroups.value[0] || '').trim()
    : ''
  const finalServiceId = isWholeProcessGroupedMode.value
    ? (() => {
      const pureRows = getPersistableRows(rowData.value)
      const hit = pureRows.find(item => String(item.serviceGroup || '').trim() === finalGroupName && item.serviceid != null)
      return hit?.serviceid ?? null
    })()
    : null
  const nextRow: WorkContentRow = {
    id: `custom-${ts}`,
    content: '',
    type: t('workContent.type.custom') as WorkType,
    serviceGroup: finalGroupName,
    serviceid: finalServiceId,
    remark: '',
    checked: false,
    custom: true,
    path: isWholeProcessGroupedMode.value && finalGroupName
      ? [finalGroupName, `${t('workContent.type.custom')}-${ts}`]
      : [t('workContent.type.custom'), `${t('workContent.type.custom')}-${ts}`]
  }
  const pureRows = getPersistableRows(rowData.value)
  pureRows.push(nextRow)
  rowData.value = withAddTriggerRows(pureRows)
  saveToStore()
  setTimeout(() => {
    const rowIndex = rowData.value.findIndex(item => item.id === nextRow.id)
    if (rowIndex >= 0) gridApi.value?.startEditingCell({ rowIndex, colKey: 'content' })
  }, 0)
}

const onGridReady = (event: GridReadyEvent<WorkContentRow>) => {
  gridApi.value = event.api
  void syncGroupedRowsRender()
}

const onFirstDataRendered = (_event: FirstDataRenderedEvent<WorkContentRow>) => {
  void syncGroupedRowsRender()
}

const onCellValueChanged = (event: CellValueChangedEvent<WorkContentRow>) => {
  const row = event.data
  if (!row || isAddTriggerRow(row)) return
  if (event.colDef.field === 'content' && row.custom) {
    const groupName = String(row.serviceGroup || '').trim()
    row.path = isWholeProcessGroupedMode.value && groupName
      ? [groupName, row.content || `${t('workContent.type.custom')}-${row.id}`]
      : [t('workContent.type.custom'), row.content || `${t('workContent.type.custom')}-${row.id}`]
  }
  if (event.colDef.field === 'type' && row.custom) {
    row.type = t('workContent.type.custom') as WorkType
  }
  saveToStore()
}

onMounted(() => {
  void loadFromStore()
})

watch(isWholeProcessGroupedMode, () => {
  void syncGroupedRowsRender()
})

watch(
    () => useDataStore().items,
    async (newItems) => {
      if (Object.keys(newItems).length > 0) {
        loadFromStore();
      }
    },
    { immediate: true, deep: true }
)

/*watch(
  () => rowData.value.length,
  () => {
    void syncGroupedRowsRender()
  }
)*/

watch(locale, () => {
  void loadFromStore()
})

onBeforeUnmount(() => {
  gridApi.value?.stopEditing()
  saveToStore()
})
const handleDeleteConfirmOpenChange = (open: boolean) => {
  deleteConfirmOpen.value = open
}


const deleteRow = (id: string) => {
  rowData.value = withAddTriggerRows(rowData.value.filter(item => item.id !== id))
  saveToStore()
}

const confirmDeleteRow = () => {
  const id = pendingDeleteRowId.value
  if (!id) return
  deleteRow(id)
  deleteConfirmOpen.value = false
  pendingDeleteRowId.value = null
  pendingDeleteRowName.value = ''
}
</script>

<template>
  <div class="h-full min-h-0 xmMx">
    <div class="h-full min-h-0 rounded-2xl border border-border/60 bg-card/90 shadow-sm backdrop-blur-sm">
      <div class="flex items-center justify-between border-b border-border/60 px-4 py-3">
        <h3 class="text-sm font-semibold text-foreground">{{ props.title || t('workContent.title') }}</h3>
      </div>
      <div class="ag-theme-quartz h-[calc(100%-56px)] min-h-0 w-full">
        <AgGridVue
          :style="agGridStyle"
          :rowData="rowData"
          :columnDefs="gridColumnDefs"
          :theme="myTheme"
          :getRowId="(params: { data: WorkContentRow }) => params.data.id"
          :treeData="true"
          :getDataPath="getDataPath"
          :groupDefaultExpanded="true ? -1 : 0"
          :groupDisplayType="true ? 'groupRows' : undefined"
          :groupRowRendererParams="groupRowRendererParams"
          :animateRows="true"
          :localeText="AG_GRID_LOCALE_CN"
          :tooltipShowDelay="500"
          :singleClickEdit="true"
          :stopEditingWhenCellsLoseFocus="true"
          :enterNavigatesVertically="true"
          :enterNavigatesVerticallyAfterEdit="true"
          :defaultColDef="defaultColDef"
          :suppressColumnVirtualisation="false"
          :suppressRowVirtualisation="false"
          @grid-ready="onGridReady"
          @first-data-rendered="onFirstDataRendered"
          @cell-value-changed="onCellValueChanged"
        />
      </div>
    </div>
    <AlertDialogRoot :open="deleteConfirmOpen" @update:open="handleDeleteConfirmOpenChange">
    <AlertDialogPortal>
      <AlertDialogOverlay class="fixed inset-0 z-50 bg-black/45" />
      <AlertDialogContent class="fixed left-1/2 top-1/2 z-[70] w-[92vw] max-w-md -translate-x-1/2 -translate-y-1/2 rounded-lg border bg-background p-5 shadow-xl">
        <AlertDialogTitle class="text-base font-semibold">{{ t('workContent.dialog.deleteTitle') }}</AlertDialogTitle>
        <AlertDialogDescription class="mt-2 text-sm text-muted-foreground">
          {{ t('workContent.dialog.deleteDesc', { name: pendingDeleteRowName }) }}
        </AlertDialogDescription>
        <div class="mt-4 flex items-center justify-end gap-2">
          <AlertDialogCancel as-child>
            <Button variant="outline">{{ t('common.cancel') }}</Button>
          </AlertDialogCancel>
          <AlertDialogAction as-child>
            <Button variant="destructive" @click="confirmDeleteRow">{{ t('common.delete') }}</Button>
          </AlertDialogAction>
        </div>
      </AlertDialogContent>
    </AlertDialogPortal>
  </AlertDialogRoot>
  </div>
</template>

<style scoped>
:deep(.ag-cell) {
  display: flex;
  align-items: center;
}

:deep(.ag-cell .ag-cell-wrapper) {
  width: 100%;
}

:deep(.ag-cell .ag-cell-value) {
  display: flex;
  align-items: center;
  width: 100%;
}
:deep(.work-content-placeholder) {
  color: var(--muted-foreground);
  font-style: italic;
  min-width: 0;
  flex: 1;
}

:deep(.work-content-cell) {
  display: flex;
  width: 100%;
  align-items: center;
  gap: 8px;
}

:deep(.work-content-text) {
  min-width: 0;
  flex: 1;
  white-space: normal;
  word-break: break-word;
  line-height: 1.5;
}

:deep(.work-content-check) {
  width: 14px;
  height: 14px;
  cursor: pointer;
}

:deep(.work-content-group-row) {
  display: flex;
  align-items: center;
  gap: 8px;
}

/* 隐藏一级分组行的复选框，但保留折叠箭头 */
:deep(.ag-group-cell .ag-cell-value .ag-cell-wrapper > input[type='checkbox']) {
  display: none !important;
}

:deep(.work-content-group-check) {
  width: 14px;
  height: 14px;
  cursor: pointer;
}

:deep(.work-content-group-check:disabled) {
  cursor: not-allowed;
  opacity: 0.5;
}

:deep(.work-content-group-label) {
  min-width: 0;
  word-break: break-word;
}

:deep(.work-content-main-cell.ag-cell-auto-height),
:deep(.remark-wrap-cell.ag-cell-auto-height) {
  display: flex;
  align-items: center;
}

:deep(.work-content-main-cell.ag-cell-auto-height .ag-cell-wrapper),
:deep(.work-content-main-cell.ag-cell-auto-height .ag-cell-value),
:deep(.remark-wrap-cell.ag-cell-auto-height .ag-cell-wrapper),
:deep(.remark-wrap-cell.ag-cell-auto-height .ag-cell-value) {
  display: flex;
  align-items: center;
  width: 100%;
}
</style>
