<script setup lang="ts">
import { computed, onActivated, onBeforeUnmount, onMounted, ref, watch } from 'vue'
import { AgGridVue } from 'ag-grid-vue3'
import type { CellValueChangedEvent, ColDef, GridApi, GridReadyEvent } from 'ag-grid-community'
import { AG_GRID_LOCALE_CN } from '@ag-grid-community/locale'
import { myTheme, gridOptions } from '@/lib/diyAgGridOptions'
import localforage from 'localforage'
import { decimalAggSum, roundTo, sumByNumber } from '@/lib/decimal'
import { formatThousands } from '@/lib/numberFormat'
import { industryTypeList } from '@/sql'
import { SwitchRoot, SwitchThumb } from 'reka-ui'

interface DetailRow {
  id: string
  groupCode: string
  groupName: string
  majorCode: string
  majorName: string
  hasCost: boolean
  hasArea: boolean
  amount: number | null
  landArea: number | null
  path: string[]
  hide?: boolean
}

interface XmBaseInfoState {
  projectIndustry?: string
}

interface GridPersistState {
  detailRows?: DetailRow[]
  roughCalcEnabled?: boolean
  totalAmount?: number | null
}

const props = defineProps<{
  title: string
  rowData: DetailRow[]
  dbKey: string
}>()

const BASE_INFO_KEY = 'xm-base-info-v1'
let persistTimer: ReturnType<typeof setTimeout> | null = null
const gridApi = ref<GridApi<DetailRow> | null>(null)
const activeIndustryId = ref('')
const industryNameMap = new Map(
  industryTypeList.flatMap(item => [
    [String(item.id).trim(), item.name],
    [String(item.type).trim(), item.name]
  ])
)
const totalLabel = computed(() => {
  const industryName = industryNameMap.get(activeIndustryId.value.trim()) || ''
  return industryName ? `${industryName}总投资` : '总投资'
})
const roughCalcEnabled = ref(false)
const visibleRowData = computed(() => props.rowData.filter(row => !row.hide))

const refreshPinnedTotalLabelCell = () => {
  if (!gridApi.value) return
  const pinnedTopNode = gridApi.value.getPinnedTopRow(0)
  if (!pinnedTopNode) return
  gridApi.value.refreshCells({
    rowNodes: [pinnedTopNode],
    force: true
  })
}

const columnDefs: ColDef<DetailRow>[] = [
  {
    headerName: '造价金额(万元)',
    field: 'amount',
    headerClass: 'ag-right-aligned-header',
    minWidth: 100,
    flex: 1,
    editable: params => {
      if (roughCalcEnabled.value) return Boolean(params.node?.rowPinned)
      return !params.node?.group && !params.node?.rowPinned && Boolean(params.data?.hasCost)
    },
    cellClass: params =>
      roughCalcEnabled.value && params.node?.rowPinned
        ? 'ag-right-aligned-cell editable-cell-line'
        : !roughCalcEnabled.value && !params.node?.group && !params.node?.rowPinned && params.data?.hasCost
        ? 'ag-right-aligned-cell editable-cell-line'
        : 'ag-right-aligned-cell',
    cellClassRules: {
      'editable-cell-empty': params =>
        roughCalcEnabled.value && params.node?.rowPinned
          ? params.value == null || params.value === ''
          : !params.node?.group && !params.node?.rowPinned && Boolean(params.data?.hasCost) && (params.value == null || params.value === '')
    },
    aggFunc: decimalAggSum,
    valueParser: params => {
      if (params.newValue === '' || params.newValue == null) return null
      const v = Number(params.newValue)
      return Number.isFinite(v) ? roundTo(v, 2) : null
    },
    valueFormatter: params => {
      if (roughCalcEnabled.value) {
        if (!params.node?.rowPinned) return ''
        if (params.value == null || params.value === '') return '点击输入'
        return formatThousands(params.value)
      }
      if (!params.node?.group && !params.node?.rowPinned && !params.data?.hasCost) {
        return ''
      }
      if (!params.node?.group && !params.node?.rowPinned && (params.value == null || params.value === '')) {
        return '点击输入'
      }
      if (params.value == null) return ''
      return formatThousands(params.value)
    }
  },
  {
    headerName: '用地面积(亩)',
    field: 'landArea',
    headerClass: 'ag-right-aligned-header',
    minWidth: 100,
    flex: 1,
    editable: params => !roughCalcEnabled.value && !params.node?.group && !params.node?.rowPinned && Boolean(params.data?.hasArea),
    cellClass: params =>
      !params.node?.group && !params.node?.rowPinned && params.data?.hasArea
        ? 'ag-right-aligned-cell editable-cell-line'
        : 'ag-right-aligned-cell',
    cellClassRules: {
      'editable-cell-empty': params =>
        !params.node?.group && !params.node?.rowPinned && Boolean(params.data?.hasArea) && (params.value == null || params.value === '')
    },
    valueParser: params => {
      if (params.newValue === '' || params.newValue == null) return null
      const v = Number(params.newValue)
      return Number.isFinite(v) ? roundTo(v, 3) : null
    },
    valueFormatter: params => {
      if (roughCalcEnabled.value) {
        return ''
      }
      if (!params.node?.group && !params.node?.rowPinned && !params.data?.hasArea) {
        return ''
      }
      if (!params.node?.group && !params.node?.rowPinned && (params.value == null || params.value === '')) {
        return '点击输入'
      }
      if (params.value == null) return ''
      return formatThousands(params.value, 3)
    }
  }
]

const autoGroupColumnDef: ColDef = {
  headerName: '专业编码以及工程专业名称',
  minWidth: 200,
  flex: 2,
  cellRendererParams: {
    suppressCount: true
  },
  valueFormatter: params => {
    if (params.node?.rowPinned) return totalLabel.value
    return String(params.value || '')
  },
  tooltipValueGetter: params => {
    if (params.node?.rowPinned) return totalLabel.value
    return String(params.value || '')
  }
}

const pinnedTopRowData = ref<DetailRow[]>([
  {
    id: 'pinned-total-row',
    groupCode: '',
    groupName: '',
    majorCode: '',
    majorName: '',
    hasCost: false,
    hasArea: false,
    amount: null,
    landArea: null,
    path: ['TOTAL']
  }
])

const saveToIndexedDB = async () => {
  try {
    const payload: GridPersistState = {
      detailRows: props.rowData.map(row => ({
        ...JSON.parse(JSON.stringify(row)),
        hide: Boolean(row.hide)
      }))
    }
    payload.roughCalcEnabled = roughCalcEnabled.value
    payload.totalAmount = pinnedTopRowData.value[0].amount
    await localforage.setItem(props.dbKey, payload)
  } catch (error) {
    console.error('saveToIndexedDB failed:', error)
  }
}

const schedulePersist = () => {
  if (persistTimer) clearTimeout(persistTimer)
  persistTimer = setTimeout(() => {
    void saveToIndexedDB()
  }, 600)
}

const setDetailRowsHidden = (hidden: boolean) => {
  for (const row of props.rowData) {
    row.hide = hidden
  }
}

const onRoughCalcSwitch = (checked: boolean) => {
  gridApi.value?.stopEditing(true)
  roughCalcEnabled.value = checked
  setDetailRowsHidden(checked)
  if (!checked) {
    syncPinnedTotalForNormalMode()
  }else{
      pinnedTopRowData.value[0].amount = null
      const pinnedTopNode = gridApi.value?.getPinnedTopRow(0)
      if (pinnedTopNode) {
        pinnedTopNode.setDataValue('amount', null)
      }
  }
  schedulePersist()
}



const onCellValueChanged = (event: CellValueChangedEvent) => {
  if (roughCalcEnabled.value && event.node?.rowPinned && event.colDef.field === 'amount') {
    if (typeof event.newValue === 'number') {
       pinnedTopRowData.value[0].amount = roundTo(event.newValue, 2)
    } else {
      const parsed = Number(event.newValue)
       pinnedTopRowData.value[0].amount = Number.isFinite(parsed) ? roundTo(parsed, 2) : null
    }

  } else if (!roughCalcEnabled.value) {
    syncPinnedTotalForNormalMode()
  }
  schedulePersist()
}

const onGridReady = (event: GridReadyEvent<DetailRow>) => {
  gridApi.value = event.api
      void loadIndustryFromBaseInfo()


  void loadGridPersistState()
    void refreshPinnedTotalLabelCell()

}

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 (error) {
    // no-op
  }
  return params.value
}

const loadIndustryFromBaseInfo = async () => {
  try {
    const baseInfo = await localforage.getItem<XmBaseInfoState>(BASE_INFO_KEY)
    activeIndustryId.value =
      typeof baseInfo?.projectIndustry === 'string' ? baseInfo.projectIndustry.trim() : ''
  } catch (error) {
    console.error('loadIndustryFromBaseInfo failed:', error)
    activeIndustryId.value = ''
  }
}

const loadGridPersistState = async () => {
  try {
    const data = await localforage.getItem<GridPersistState>(props.dbKey)
    roughCalcEnabled.value = Boolean(data?.roughCalcEnabled)
    const detailRows = Array.isArray(data?.detailRows) ? data.detailRows : []
    const detailRowById = new Map(detailRows.map(row => [row.id, row]))
    for (const row of props.rowData) {
      const persisted = detailRowById.get(row.id)
      if (!persisted) {
        row.hide = roughCalcEnabled.value
        continue
      }
      row.amount = typeof persisted.amount === 'number' ? roundTo(persisted.amount, 2) : null
      row.landArea = typeof persisted.landArea === 'number' ? roundTo(persisted.landArea, 3) : null
      row.hide = typeof persisted.hide === 'boolean' ? persisted.hide : roughCalcEnabled.value
    }
    pinnedTopRowData.value[0].amount = typeof data?.totalAmount === 'number' ? data.totalAmount : null

  const pinnedTopNode = (gridApi as any).value.getPinnedTopRow(0)
    if (pinnedTopNode) {
      pinnedTopNode.setDataValue('amount',   pinnedTopRowData.value[0].amount)
    }
  } catch (error) {
    console.error('loadGridPersistState failed:', error)
    roughCalcEnabled.value = false
    pinnedTopRowData.value[0].amount= null
  }
}



watch(totalLabel, () => {
  refreshPinnedTotalLabelCell()
})

const syncPinnedTotalForNormalMode = () => {
  if (roughCalcEnabled.value) return

  if (!gridApi.value) {
    pinnedTopRowData.value[0].amount = sumByNumber(props.rowData, row => row.amount)
    return
  }
  let total = 0
  let hasValue = false

 props.rowData.forEach(node => {
   
    const amount = node.amount
    if (typeof amount === 'number' && Number.isFinite(amount)) {
      total += amount
      hasValue = true
    }
  })
  pinnedTopRowData.value[0].amount = hasValue ? roundTo(total, 2) : null
  const pinnedTopNode = gridApi.value.getPinnedTopRow(0)
    if (pinnedTopNode) {
      pinnedTopNode.setDataValue('amount', hasValue ? roundTo(total, 2) : null)
    }
}

onBeforeUnmount(() => {
  if (persistTimer) clearTimeout(persistTimer)
  gridApi.value = null
  void saveToIndexedDB()
})
</script>

<template>
  <div class="h-full">
    <div class="rounded-lg border bg-card xmMx scroll-mt-3 flex flex-col overflow-hidden h-full">
      <div class="flex items-center justify-between border-b px-4 py-3">
        <h3 class="text-sm font-semibold text-foreground cursor-pointer select-none transition-colors hover:text-primary">
          {{ props.title }}
        </h3>
        <div class="flex items-center gap-2">
          <span class=" text-xs text-muted-foreground">粗略计算</span>
          <SwitchRoot
            class="cursor-pointer peer h-5 w-9 shrink-0 rounded-full border border-transparent bg-muted shadow-sm transition-colors data-[state=checked]:bg-primary"
            :modelValue="roughCalcEnabled"
            @update:modelValue="onRoughCalcSwitch"
          >
            <SwitchThumb
              class="block h-4 w-4 translate-x-0.5 rounded-full bg-background shadow transition-transform data-[state=checked]:translate-x-4"
            />
          </SwitchRoot>
        </div>
      </div>

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