<script setup lang="ts">
import { computed } from 'vue'
import { AgGridVue } from 'ag-grid-vue3'
import {
  ClientSideRowModelModule,
  ColumnAutoSizeModule,
  CellStyleModule,
  ValidationModule,
  TextFilterModule,
  TextEditorModule,
  NumberEditorModule,
  SelectEditorModule,
  UndoRedoEditModule,
  RowStyleModule,
  RenderApiModule,
  themeQuartz,
  ModuleRegistry,
  RowSelectionModule,
  type ColDef,
  type RowClickedEvent,
  type CellValueChangedEvent,
  type RowClassParams
} from 'ag-grid-community'
import type { UiGridColumn } from '../contracts'

ModuleRegistry.registerModules([
  ClientSideRowModelModule,
  ColumnAutoSizeModule,
  CellStyleModule,
  ValidationModule,
  TextFilterModule,
  TextEditorModule,
  NumberEditorModule,
  SelectEditorModule,
  UndoRedoEditModule,
  RowStyleModule,
  RenderApiModule,
  RowSelectionModule
])



const props = withDefaults(defineProps<{
  rows: unknown[]
  columns: UiGridColumn[]
  loading?: boolean
  height?: string
  rowSelection?: 'single' | 'multiple' | 'none'
}>(), { loading: false, height: '32rem', rowSelection: 'single' })

const emit = defineEmits<{ rowSelected: [row: unknown]; cellValueChanged: [event: CellValueChangedEvent] }>()

const columnDefs = computed<ColDef[]>(() => props.columns.map(column => ({
  field: column.field,
  headerName: column.header,
  width: column.width,
  minWidth: column.minWidth ?? 120,
  maxWidth: column.maxWidth,

  sortable: column.sortable ?? true,
  filter: column.filterable ?? false,
  editable: column.editable ?? false,

  valueFormatter: column.formatter
    ? params => column.formatter?.(params.value, params.data) ?? ''
    : undefined
})))

const rowClassRules = computed(() => ({
  'ks-row-added': (params: RowClassParams) => {
    const data = params.data as Record<string, unknown> | undefined
    if (!data) return false
    return !!(data._isNew || (typeof data.code === 'string' && data.code.startsWith('NEW_')) || (typeof data.groupCode === 'string' && data.groupCode.startsWith('NEW_')))
  },
  'ks-row-modified': (params: RowClassParams) => {
    const data = params.data as Record<string, unknown> | undefined
    return data?._isModified === true
  }
}))

const rowSelectionOptions = computed(() => {
  if (props.rowSelection === 'none') return undefined
  if (props.rowSelection === 'multiple') return { mode: 'multiRow' } as const
  return { mode: 'singleRow', checkboxes: false, enableClickSelection: true } as const
})


function onRowClicked(event: RowClickedEvent): void {
  if (event.data) emit('rowSelected', event.data)
}

function onCellValueChanged(event: CellValueChangedEvent): void {
  if (event.data) {
    (event.data as Record<string, unknown>)._isModified = true
    event.api.redrawRows()
    emit('cellValueChanged', event)
  }
}

import type { NavigateToNextCellParams, CellPosition, CellEditingStoppedEvent, CellKeyDownEvent } from 'ag-grid-community'

let isEnterKeyPressed = false

function onCellKeyDown(event: CellKeyDownEvent): void {
  const keyboardEvent = event.event as KeyboardEvent
  if (keyboardEvent && (keyboardEvent.key === 'Enter' || String(keyboardEvent.key) === '13')) {
    isEnterKeyPressed = true
  }
}

function onCellEditingStopped(event: CellEditingStoppedEvent): void {
  if (isEnterKeyPressed && event.api) {
    isEnterKeyPressed = false
    const api = event.api
    const rowIndex = event.rowIndex
    const colKey = event.column.getColId()

    if (rowIndex === null || rowIndex === undefined) return

    const allCols = api.getAllGridColumns()
    const editableCols = allCols.filter(c => {
      const colDef = c.getColDef()
      return colDef.editable === true || typeof colDef.editable === 'function'
    })

    const currIdx = editableCols.findIndex(c => c.getColId() === colKey)

    if (currIdx >= 0 && currIdx < editableCols.length - 1) {
      const nextColId = editableCols[currIdx + 1].getColId()
      setTimeout(() => {
        api.setFocusedCell(rowIndex, nextColId)
        api.startEditingCell({ rowIndex, colKey: nextColId })
      }, 40)
    } else {
      const nextRowIdx = rowIndex + 1
      const firstColId = editableCols[0]?.getColId()
      if (firstColId && nextRowIdx < api.getDisplayedRowCount()) {
        setTimeout(() => {
          api.ensureIndexVisible(nextRowIdx)
          api.setFocusedCell(nextRowIdx, firstColId)
          api.startEditingCell({ rowIndex: nextRowIdx, colKey: firstColId })
        }, 40)
      }
    }
  }
}

function navigateToNextCell(params: NavigateToNextCellParams): CellPosition | null {
  const previousCell = params.previousCellPosition
  const suggestedNextCell = params.nextCellPosition

  if (params.key === 'Enter' || String(params.key) === '13') {
    const allColumns = params.api.getAllGridColumns()
    const editableCols = allColumns.filter(c => {
      const colDef = c.getColDef()
      return colDef.editable === true || typeof colDef.editable === 'function'
    })

    if (editableCols.length > 0) {
      const currentColId = previousCell.column.getColId()
      const currentIndex = editableCols.findIndex(c => c.getColId() === currentColId)

      if (currentIndex >= 0 && currentIndex < editableCols.length - 1) {
        const nextCol = editableCols[currentIndex + 1]
        const colId = nextCol.getColId()
        setTimeout(() => {
          params.api.startEditingCell({ rowIndex: previousCell.rowIndex, colKey: colId })
        }, 30)
        return {
          rowIndex: previousCell.rowIndex,
          column: nextCol,
          rowPinned: previousCell.rowPinned
        }
      } else {
        const nextRowIndex = previousCell.rowIndex + 1
        const firstCol = editableCols[0]
        const colId = firstCol.getColId()
        setTimeout(() => {
          params.api.startEditingCell({ rowIndex: nextRowIndex, colKey: colId })
        }, 30)
        return {
          rowIndex: nextRowIndex,
          column: firstCol,
          rowPinned: previousCell.rowPinned
        }
      }
    }
  }

  return suggestedNextCell
}

</script>

<template>
  <div class="ks-grid" :style="{ height }" :aria-busy="loading">
    <AgGridVue
      style="height: 100%; width: 100%"
      :theme="themeQuartz"
      :row-data="rows"
      :column-defs="columnDefs"
      :row-selection="rowSelectionOptions"
      :row-class-rules="rowClassRules"
      :enter-navigates-to-next-cell="true"
      :enter-navigates-to-next-cell-after-edit="true"
      :navigate-to-next-cell="navigateToNextCell"
      :stop-editing-when-cells-lose-focus="true"
      :loading="loading"
      :suppress-no-rows-overlay="rows.length > 0"
      @row-clicked="onRowClicked"
      @cell-value-changed="onCellValueChanged"
      @cell-key-down="onCellKeyDown"
      @cell-editing-stopped="onCellEditingStopped"
    />
  </div>
</template>




<style scoped>
.ks-grid {
  min-height: 12rem;
  border: 1px solid var(--ks-color-neutral-200);
  border-radius: var(--ks-radius-md);
  overflow: hidden;
  background: #fff;
}
</style>
