<script setup lang="ts">
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
import { AgGridVue } from 'ag-grid-vue3'
import type { ColDef, GridOptions } from 'ag-grid-community'
import localforage from 'localforage'
import { majorList } from '@/sql'
import 'ag-grid-enterprise'
import {  myTheme } from '@/lib/diyAgGridTheme'

import { AG_GRID_LOCALE_CN } from '@ag-grid-community/locale';
// 精简的边框配置（细线条+浅灰色，弱化分割线视觉）

interface DictLeaf {
  id: string
  code: string
  name: string
}

interface DictGroup {
  id: string
  code: string
  name: string
  children: DictLeaf[]
}

interface DetailRow {
  id: string
  groupCode: string
  groupName: string
  majorCode: string
  majorName: string
  amount: number | null
  landArea: number | null
  benchmarkBudget: number | null
  consultCategoryFactor: number | null
  majorFactor: number | null
  budgetFee: number | null
  remark: string
  path: string[]
}

interface XmInfoState {
  projectName: string
  detailRows: DetailRow[]
}

const props = defineProps<{
  contractId: string,
  serviceId: string|number
}>()
const DB_KEY = computed(() => `ydGMF-${props.contractId}-${props.serviceId}`)

const detailRows = ref<DetailRow[]>([])

type majorLite = { code: string; name: string }
const serviceEntries = Object.entries(majorList as Record<string, majorLite>)
  .sort((a, b) => Number(a[0]) - Number(b[0]))
  .filter((entry): entry is [string, majorLite] => {
    const item = entry[1]
    return Boolean(item?.code && item?.name)
  })

const detailDict: DictGroup[] = (() => {
  const groupMap = new Map<string, DictGroup>()
  const groupOrder: string[] = []
  const codeLookup = new Map(serviceEntries.map(([key, item]) => [item.code, { id: key, code: item.code, name: item.name }]))

  for (const [key, item] of serviceEntries) {
    const code = item.code
    const isGroup = !code.includes('-')
    if (isGroup) {
      if (!groupMap.has(code)) groupOrder.push(code)
      groupMap.set(code, {
        id: key,
        code,
        name: item.name,
        children: []
      })
      continue
    }

    const parentCode = code.split('-')[0]
    if (!groupMap.has(parentCode)) {
      const parent = codeLookup.get(parentCode)
      if (!groupOrder.includes(parentCode)) groupOrder.push(parentCode)
      groupMap.set(parentCode, {
        id: parent?.id || `group-${parentCode}`,
        code: parentCode,
        name: parent?.name || parentCode,
        children: []
      })
    }

    groupMap.get(parentCode)!.children.push({
      id: key,
      code,
      name: item.name
    })
  }

  return groupOrder.map(code => groupMap.get(code)).filter((group): group is DictGroup => Boolean(group))
})()

const idLabelMap = new Map<string, string>()
for (const group of detailDict) {
  idLabelMap.set(group.id, `${group.code} ${group.name}`)
  for (const child of group.children) {
    idLabelMap.set(child.id, `${child.code} ${child.name}`)
  }
}

const buildDefaultRows = (): DetailRow[] => {
  const rows: DetailRow[] = []
  for (const group of detailDict) {
    for (const child of group.children) {
      rows.push({
        id: child.id,
        groupCode: group.code,
        groupName: group.name,
        majorCode: child.code,
        majorName: child.name,
        amount: null,
        landArea: null,
        benchmarkBudget: null,
        consultCategoryFactor: null,
        majorFactor: null,
        budgetFee: null,
        remark: '',
        path: [group.id, child.id]
      })
    }
  }
  return rows
}

const mergeWithDictRows = (rowsFromDb: DetailRow[] | undefined): DetailRow[] => {
  const dbValueMap = new Map<string, DetailRow>()
  for (const row of rowsFromDb || []) {
    dbValueMap.set(row.id, row)
  }

  return buildDefaultRows().map(row => {
    const fromDb = dbValueMap.get(row.id)
    if (!fromDb) return row

    return {
      ...row,
      amount: typeof fromDb.amount === 'number' ? fromDb.amount : null,
      landArea: typeof fromDb.landArea === 'number' ? fromDb.landArea : null,
      benchmarkBudget: typeof fromDb.benchmarkBudget === 'number' ? fromDb.benchmarkBudget : null,
      consultCategoryFactor:
        typeof fromDb.consultCategoryFactor === 'number' ? fromDb.consultCategoryFactor : null,
      majorFactor: typeof fromDb.majorFactor === 'number' ? fromDb.majorFactor : null,
      budgetFee: typeof fromDb.budgetFee === 'number' ? fromDb.budgetFee : null,
      remark: typeof fromDb.remark === 'string' ? fromDb.remark : ''
    }
  })
}

const parseNumberOrNull = (value: unknown) => {
  if (value === '' || value == null) return null
  const v = Number(value)
  return Number.isFinite(v) ? v : null
}

const formatEditableNumber = (params: any) => {
  if (!params.node?.group && !params.node?.rowPinned && (params.value == null || params.value === '')) {
    return '点击输入'
  }
  if (params.value == null) return ''
  return Number(params.value).toFixed(2)
}

const columnDefs: ColDef<DetailRow>[] = [
  {
    headerName: '工程专业名称',
    minWidth: 220,
    width: 240,
    pinned: 'left',
    valueGetter: params => {
      if (params.node?.rowPinned) return ''
      return params.node?.group ? params.data?.groupName || '' : params.data?.majorName || ''
    }
  },
  {
    headerName: '用地面积(亩)',
    field: 'landArea',
    minWidth: 170,
    flex: 1,

    editable: params => !params.node?.group && !params.node?.rowPinned,
    cellClass: params => (!params.node?.group && !params.node?.rowPinned ? 'editable-cell-line' : ''),
    cellClassRules: {
      'editable-cell-empty': params =>
        !params.node?.group && !params.node?.rowPinned && (params.value == null || params.value === '')
    },
    aggFunc: 'sum',
    valueParser: params => parseNumberOrNull(params.newValue),
    valueFormatter: formatEditableNumber
  },
  {
    headerName: '基准预算(元)',
    field: 'benchmarkBudget',
    minWidth: 170,
    flex: 1,
    editable: params => !params.node?.group && !params.node?.rowPinned,
    cellClass: params => (!params.node?.group && !params.node?.rowPinned ? 'editable-cell-line' : ''),
    cellClassRules: {
      'editable-cell-empty': params =>
        !params.node?.group && !params.node?.rowPinned && (params.value == null || params.value === '')
    },
    aggFunc: 'sum',
    valueParser: params => parseNumberOrNull(params.newValue),
    valueFormatter: formatEditableNumber
  },
  {
    headerName: '咨询分类系数',
    field: 'consultCategoryFactor',
    minWidth: 150,
    flex: 1,
    editable: params => !params.node?.group && !params.node?.rowPinned,
    cellClass: params => (!params.node?.group && !params.node?.rowPinned ? 'editable-cell-line' : ''),
    cellClassRules: {
      'editable-cell-empty': params =>
        !params.node?.group && !params.node?.rowPinned && (params.value == null || params.value === '')
    },
    valueParser: params => parseNumberOrNull(params.newValue),
    valueFormatter: formatEditableNumber
  },
  {
    headerName: '专业系数',
    field: 'majorFactor',
    minWidth: 130,
    flex: 1,
    editable: params => !params.node?.group && !params.node?.rowPinned,
    cellClass: params => (!params.node?.group && !params.node?.rowPinned ? 'editable-cell-line' : ''),
    cellClassRules: {
      'editable-cell-empty': params =>
        !params.node?.group && !params.node?.rowPinned && (params.value == null || params.value === '')
    },
    valueParser: params => parseNumberOrNull(params.newValue),
    valueFormatter: formatEditableNumber
  },
  {
    headerName: '预算费用',
    field: 'budgetFee',
    minWidth: 150,
    flex: 1,
    editable: params => !params.node?.group && !params.node?.rowPinned,
    cellClass: params => (!params.node?.group && !params.node?.rowPinned ? 'editable-cell-line' : ''),
    cellClassRules: {
      'editable-cell-empty': params =>
        !params.node?.group && !params.node?.rowPinned && (params.value == null || params.value === '')
    },
    aggFunc: 'sum',
    valueParser: params => parseNumberOrNull(params.newValue),
    valueFormatter: formatEditableNumber
  },
  {
    headerName: '说明',
    field: 'remark',
    minWidth: 180,
    flex: 1.2,
    editable: params => !params.node?.group && !params.node?.rowPinned,
    valueFormatter: params => {
      if (!params.node?.group && !params.node?.rowPinned && !params.value) return '点击输入'
      return params.value || ''
    },
    cellClass: params => (!params.node?.group && !params.node?.rowPinned ? 'editable-cell-line' : ''),
    cellClassRules: {
      'editable-cell-empty': params =>
        !params.node?.group && !params.node?.rowPinned && (params.value == null || params.value === '')
    }
  }
]

const autoGroupColumnDef: ColDef = {
  headerName: '专业编码',
  minWidth: 160,
  pinned: 'left',
  width: 170,

  cellRendererParams: {
    suppressCount: true
  },
  valueFormatter: params => {
    if (params.node?.rowPinned) {
      return '总合计'
    }
    const nodeId = String(params.value || '')
    const label = idLabelMap.get(nodeId) || nodeId
    return label.includes(' ') ? label.split(' ')[0] : label
  }
}

const gridOptions: GridOptions<DetailRow> = {
  treeData: true,
  animateRows: true,
  singleClickEdit: true,
  suppressClickEdit: false,
  suppressContextMenu: false,
  groupDefaultExpanded: -1,
  suppressFieldDotNotation: true,
  getDataPath: data => data.path,
  getContextMenuItems: () => ['copy', 'paste', 'separator', 'export'],
  defaultColDef: {
    resizable: true,
    sortable: false,
    filter: false
  }
}

const totalAmount = computed(() =>
  detailRows.value.reduce((sum, row) => sum + (row.amount || 0), 0)
)

const totalLandArea = computed(() =>
  detailRows.value.reduce((sum, row) => sum + (row.landArea || 0), 0)
)

const totalBenchmarkBudget = computed(() =>
  detailRows.value.reduce((sum, row) => sum + (row.benchmarkBudget || 0), 0)
)

const totalBudgetFee = computed(() =>
  detailRows.value.reduce((sum, row) => sum + (row.budgetFee || 0), 0)
)
const pinnedTopRowData = computed(() => [
  {
    id: 'pinned-total-row',
    groupCode: '',
    groupName: '',
    majorCode: '',
    majorName: '',
    amount: totalAmount.value,
    landArea: totalLandArea.value,
    benchmarkBudget: totalBenchmarkBudget.value,
    consultCategoryFactor: null,
    majorFactor: null,
    budgetFee: totalBudgetFee.value,
    remark: '',
    path: ['TOTAL']
  }
])



const saveToIndexedDB = async () => {
  try {
    const payload = {
  detailRows: JSON.parse(JSON.stringify(detailRows.value)) 
    }
    console.log('Saving to IndexedDB:', payload)
    await localforage.setItem(DB_KEY.value, payload)
  } catch (error) {
    console.error('saveToIndexedDB failed:', error)
  }
}

const loadFromIndexedDB = async () => {
  try {
    const data = await localforage.getItem<XmInfoState>(DB_KEY.value)
    if (data) {
      detailRows.value = mergeWithDictRows(data.detailRows)
      return
    }

    detailRows.value = buildDefaultRows()
  } catch (error) {
    console.error('loadFromIndexedDB failed:', error)
    detailRows.value = buildDefaultRows()
  }
}

let persistTimer: ReturnType<typeof setTimeout> | null = null




let gridPersistTimer: ReturnType<typeof setTimeout> | null = null
const handleCellValueChanged = () => {
  if (gridPersistTimer) clearTimeout(gridPersistTimer)
  gridPersistTimer = setTimeout(() => {
    void saveToIndexedDB()
  }, 1000)
}


onMounted(async () => {
  await loadFromIndexedDB()
})

onBeforeUnmount(() => {
  if (persistTimer) clearTimeout(persistTimer)
  if (gridPersistTimer) clearTimeout(gridPersistTimer)
  void saveToIndexedDB()
})
const processCellForClipboard = (params:any) => {
  if (Array.isArray(params.value)) {
    return JSON.stringify(params.value); // 数组转字符串复制
  }
  return params.value;
};

const processCellFromClipboard = (params:any) => {
  try {
    const parsed = JSON.parse(params.value);
    if (Array.isArray(parsed)) return parsed;
  } catch (e) {
    // 解析失败时返回原始值，无需额外处理
  }
  return params.value;
};
</script>

<template>
  <div class="h-full min-h-0 flex flex-col">
  

    <div class="rounded-lg border bg-card xmMx flex min-h-0 flex-1 flex-col">
      <div class="flex items-center justify-between border-b px-4 py-3">
        <h3 class="text-sm font-semibold text-foreground">用地规模明细</h3>
        <div class="text-xs text-muted-foreground">导入导出</div>
      </div>

      <div class="ag-theme-quartz h-full min-h-0 w-full flex-1">
         <AgGridVue
    :style="{ height: '100%' }"
    :rowData="detailRows"
    :pinnedTopRowData="pinnedTopRowData"
    :columnDefs="columnDefs"
    :autoGroupColumnDef="autoGroupColumnDef"
    :gridOptions="gridOptions"
    :theme="myTheme"
    @cell-value-changed="handleCellValueChanged"
    :suppressColumnVirtualisation="true"
    :suppressRowVirtualisation="true"
    :cellSelection="{ handle: { mode: 'range' } }"
    :enableClipboard="true"
    :localeText="AG_GRID_LOCALE_CN"
    :tooltipShowDelay="500"
        :headerHeight="50"
    :processCellForClipboard="processCellForClipboard"
    :processCellFromClipboard="processCellFromClipboard"
    :undoRedoCellEditing="true"
    :undoRedoCellEditingLimit="20"

  />
      </div>
    </div>
  </div>
</template>

<style >
.ag-floating-top{
  overflow-y:auto !important
}

.xmMx .editable-cell-line .ag-cell-value {
  display: inline-block;
  min-width: 84%;
  padding: 2px 4px;
  border-bottom: 1px solid #cbd5e1;
}

.xmMx .editable-cell-line.ag-cell-focus .ag-cell-value,
.xmMx .editable-cell-line:hover .ag-cell-value {
  border-bottom-color: #2563eb;
}

.xmMx .editable-cell-empty .ag-cell-value {
  color: #94a3b8 !important;
  font-style: italic;
  opacity: 1 !important;
}

.xmMx .ag-cell.editable-cell-empty,
.xmMx .ag-cell.editable-cell-empty .ag-cell-value {
  color: #94a3b8 !important;
}
</style>
