<script setup lang="ts">
import { onActivated, onBeforeUnmount, onMounted, ref, watch } from 'vue'
import { AgGridVue } from 'ag-grid-vue3'
import type { ColDef, GridApi, GridOptions, GridReadyEvent } from 'ag-grid-community'
import { AG_GRID_LOCALE_CN } from '@ag-grid-community/locale'
import localforage from 'localforage'
import { myTheme, gridOptions } from '@/lib/diyAgGridOptions'
import { parseNumberOrNull } from '@/lib/number'
import { formatThousands, formatThousandsFlexible } from '@/lib/numberFormat'
import { roundTo, toDecimal } from '@/lib/decimal'

interface FeeRow {
  id: string
  feeItem: string
  unit: string
  quantity: number | null
  unitPrice: number | null
  budgetFee: number | null
  remark: string
}

interface FeeGridState {
  detailRows: FeeRow[]
}

const props = defineProps<{
  title: string
  storageKey: string
}>()

const createRowId = () => `fee-${Date.now()}-${Math.random().toString(16).slice(2, 8)}`

const createDefaultRow = (): FeeRow => ({
  id: createRowId(),
  feeItem: '',
  unit: '',
  quantity: null,
  unitPrice: null,
  budgetFee: null,
  remark: ''
})

const detailRows = ref<FeeRow[]>([createDefaultRow()])
const gridApi = ref<GridApi<FeeRow> | null>(null)

const formatEditableText = (params: any) => {
  if (params.value == null || params.value === '') return '点击输入'
  return String(params.value)
}

const formatEditableQuantity = (params: any) => {
  if (params.value == null || params.value === '') return '点击输入'
  return formatThousandsFlexible(params.value, 4)
}

const formatEditableUnitPrice = (params: any) => {
  if (params.value == null || params.value === '') return '点击输入'
  return formatThousands(params.value, 2)
}

const formatReadonlyBudgetFee = (params: any) => {
  if (params.value == null || params.value === '') return ''
  return formatThousands(params.value, 2)
}

const syncComputedValuesToRows = () => {
  for (const row of detailRows.value) {
    if (row.quantity == null || row.unitPrice == null) {
      row.budgetFee = null
      continue
    }
    row.budgetFee = roundTo(toDecimal(row.quantity).mul(row.unitPrice), 2)
  }
}

const mergeWithStoredRows = (rowsFromDb: unknown): FeeRow[] => {
  if (!Array.isArray(rowsFromDb) || rowsFromDb.length === 0) {
    return [createDefaultRow()]
  }

  const rows: FeeRow[] = rowsFromDb.map(item => {
    const row = item as Partial<FeeRow>
    return {
      id: typeof row.id === 'string' && row.id ? row.id : createRowId(),
      feeItem: typeof row.feeItem === 'string' ? row.feeItem : '',
      unit: typeof row.unit === 'string' ? row.unit : '',
      quantity: typeof row.quantity === 'number' ? row.quantity : null,
      unitPrice: typeof row.unitPrice === 'number' ? row.unitPrice : null,
      budgetFee: typeof row.budgetFee === 'number' ? row.budgetFee : null,
      remark: typeof row.remark === 'string' ? row.remark : ''
    }
  })

  return rows.length > 0 ? rows : [createDefaultRow()]
}

const buildPersistDetailRows = () => {
  syncComputedValuesToRows()
  return detailRows.value.map(row => ({ ...row }))
}

const saveToIndexedDB = async () => {
  try {
    const payload: FeeGridState = {
      detailRows: JSON.parse(JSON.stringify(buildPersistDetailRows()))
    }
    await localforage.setItem(props.storageKey, payload)
  } catch (error) {
    console.error('saveToIndexedDB failed:', error)
  }
}

const loadFromIndexedDB = async () => {
  try {
    const data = await localforage.getItem<FeeGridState>(props.storageKey)
    detailRows.value = mergeWithStoredRows(data?.detailRows)
    syncComputedValuesToRows()
  } catch (error) {
    console.error('loadFromIndexedDB failed:', error)
    detailRows.value = [createDefaultRow()]
    syncComputedValuesToRows()
  }
}

const columnDefs: ColDef<FeeRow>[] = [
  {
    headerName: '费用项',
    field: 'feeItem',
    minWidth: 140,
    flex: 1.4,
    editable: true,
    valueFormatter: formatEditableText,
    cellClass: 'editable-cell-line',
    cellClassRules: {
      'editable-cell-empty': params => params.value == null || params.value === ''
    }
  },
  {
    headerName: '单位',
    field: 'unit',
    minWidth: 90,
    flex: 0.9,
    editable: true,
    valueFormatter: formatEditableText,
    cellClass: 'editable-cell-line',
    cellClassRules: {
      'editable-cell-empty': params => params.value == null || params.value === ''
    }
  },
  {
    headerName: '数量',
    field: 'quantity',
    minWidth: 100,
    flex: 1,
    headerClass: 'ag-right-aligned-header',
    cellClass: 'ag-right-aligned-cell editable-cell-line',
    editable: true,
    valueParser: params => parseNumberOrNull(params.newValue, { precision: 4 }),
    valueFormatter: formatEditableQuantity,
    cellClassRules: {
      'editable-cell-empty': params => params.value == null || params.value === ''
    }
  },
  {
    headerName: '单价(元)',
    field: 'unitPrice',
    minWidth: 120,
    flex: 1.1,
    headerClass: 'ag-right-aligned-header',
    cellClass: 'ag-right-aligned-cell editable-cell-line',
    editable: true,
    valueParser: params => parseNumberOrNull(params.newValue, { precision: 2 }),
    valueFormatter: formatEditableUnitPrice,
    cellClassRules: {
      'editable-cell-empty': params => params.value == null || params.value === ''
    }
  },
  {
    headerName: '预算费用(元)',
    field: 'budgetFee',
    minWidth: 130,
    flex: 1.2,
    headerClass: 'ag-right-aligned-header',
    cellClass: 'ag-right-aligned-cell',
    editable: false,
    valueFormatter: formatReadonlyBudgetFee
  },
  {
    headerName: '说明',
    field: 'remark',
    minWidth: 170,
    flex: 2,
    editable: true,
    cellEditor: 'agLargeTextCellEditor',
    wrapText: true,
    autoHeight: true,
    cellStyle: { whiteSpace: 'normal', lineHeight: '1.4' },
    valueFormatter: formatEditableText,
    cellClass: 'editable-cell-line remark-wrap-cell',
    cellClassRules: {
      'editable-cell-empty': params => params.value == null || params.value === ''
    }
  }
]

const detailGridOptions: GridOptions<FeeRow> = {
  ...gridOptions,
  treeData: false
}

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

const handleGridReady = (event: GridReadyEvent<FeeRow>) => {
  gridApi.value = event.api
}

const handleCellValueChanged = () => {
  syncComputedValuesToRows()
  gridApi.value?.refreshCells({ columns: ['budgetFee'], force: true })
  if (gridPersistTimer) clearTimeout(gridPersistTimer)
  gridPersistTimer = setTimeout(() => {
    void saveToIndexedDB()
  }, 300)
}

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

onActivated(() => {
  void loadFromIndexedDB()
})

watch(
  () => props.storageKey,
  () => {
    void loadFromIndexedDB()
  }
)

onBeforeUnmount(() => {
  if (gridPersistTimer) clearTimeout(gridPersistTimer)
  gridApi.value = null
  void saveToIndexedDB()
})
</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">{{ title }}</h3>
      </div>

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