import { forwardRef, useContext, useEffect, useImperativeHandle, useState } from "react"

//import { getEditCellRender } from './RenderCell'
import { DataGrid, GridRowId, GridRowModel, useGridApiRef } from "@mui/x-data-grid"
import { Button, Stack } from "@mui/material"
import { EditorProperties, getDefaultValue } from "@iplusplus/y-model"
import { checkCanEdit } from "../convention"
import { EditorContext } from "../editor-context"

import SwapVertIcon from '@mui/icons-material/SwapVert';
import AddIcon from '@mui/icons-material/Add';
import RemoveIcon from '@mui/icons-material/Remove';
import ArrowUpwardIcon from '@mui/icons-material/ArrowUpward';
import ArrowDownwardIcon from '@mui/icons-material/ArrowDownward';
import { CustomIcon } from "../ui-utils"


function translateNumberValue(properties: EditorProperties, newRow: GridRowModel, oldRow: GridRowModel) {
  const result = { ...newRow }
  properties.forEach(p => {
    if (p.valueType.dataTypeName === "number" && typeof result[p.name] !== "number") {
      let newNumberValue = parseFloat(result[p.name])
      if (isNaN(newNumberValue)) newNumberValue = oldRow[p.name]
      result[p.name] = newNumberValue
    }
  })
  return result
}

function createProcessRowUpdate(
  properties: EditorProperties,
  onRowUpdate: (newData: Record<string, undefined>) => void,
) {
  return (newRow: GridRowModel, oldRow: GridRowModel) =>
    new Promise<GridRowModel>(resolve => {
      const newRowCopy = translateNumberValue(properties, newRow, oldRow)
      resolve(newRowCopy)
      onRowUpdate(newRowCopy)
    })
}

export type ObjectArrayEditorHandler = {
  getData(): Record<string, unknown>[]
}

let gTmpId = 0
function uid() {
  return gTmpId++
}

function assignId(data: Record<string, unknown>[]): Record<string, unknown>[] {
  return data.map(d => ({
    id: uid(),
    ...d,
  }))
}

function swapArrayItem(arr: unknown[], pos1: number, pos2: number) {
  const tmp = arr[pos1]
  arr[pos1] = arr[pos2]
  arr[pos2] = tmp
}

export type ObjectArrayEditorDetail = {
  disableAdd?: boolean,
  disableDelete?: boolean
}

export type ObjectArrayEditorProps = {
  properties: EditorProperties
  data: Record<string, unknown>[]
  newRowProvider?: (currentRows: Record<string, unknown>[]) => Promise<Record<string, unknown>[]>
  onlyEdit?: boolean,
  refreshByData?: boolean,
  details?: ObjectArrayEditorDetail
}

function reverseArrayByIndexes<T>(arr:T[],indexes:number[]){
  //这个函数用于逆序一个数组中的指定项, arr表示目标数组, indexes表示需要逆序的项的下标
  // 示例输出: reverseArrayByIndexes([0,1,2,3,4,5],[1,3,4])=>[0,4,2,3,1,5]
  const values = indexes.map(i => arr[i]);
  const reversed = values.reverse();
  const result = [...arr];
  indexes.forEach((idx, i) => {
    result[idx] = reversed[i];
  });
  return result;
}

export const ObjectArrayEditor = forwardRef<
  ObjectArrayEditorHandler,
  ObjectArrayEditorProps
>(function ({ properties, data, newRowProvider, onlyEdit, refreshByData, details }, ref) {
  const [rows, setRows] = useState(() => assignId(data))
  // const [currentData, setCurrentData] = useState(data);
  const apiRef = useGridApiRef()
  const [lastEditField, setLastEditField] = useState("")
  const disableAdd = details && details.disableAdd;
  const disableDelete = details && details.disableDelete;
  useEffect(() => {
    if (refreshByData) {
      setRows(() => assignId(data))
    }
  }, [refreshByData, data])

  const getData: () => Record<string, unknown>[] = () => {
    // const rowModels = apiRef.current.getRowModels();
    const result: Record<string, unknown>[] = []
    rows.forEach(v => {
      //make eslint happy
      const { id: _id, ...remains } = v
      result.push(remains)
    })
    return result
  }

  useImperativeHandle(ref, () => ({
    getData,
  }))

  const processRowUpdate = createProcessRowUpdate(properties, newRow => {
    if (!lastEditField) return
    console.log(lastEditField)
    const newValue = newRow[lastEditField]
    const selectRows = apiRef.current.getSelectedRows()
    const newRows = rows.map(r => {
      const id = r.id as GridRowId
      if (id === newRow.id || selectRows.get(id)) {
        return { ...r, [lastEditField]: newValue }
      }
      return r
    })
    console.log(newRows)
    setRows(newRows)
  })

  const addRowDefault = () => {
    const newRow = getDefaultValue(properties)
    newRow.id = uid()
    const newRows = [...rows, newRow]
    console.log(newRows)
    setRows(newRows)
  }

  const addRow = newRowProvider
    ? () => {
      newRowProvider(rows).then(newRows => {
        const newRows3 = assignId(newRows)
        const newRows2 = [...rows, ...newRows3]
        console.log(newRows2)

        setRows(newRows2)
      })
    }
    : addRowDefault

  const deleteRow = () => {
    const selectedRows = apiRef.current.getSelectedRows()
    const newRows = rows.filter(r => !selectedRows.has(r.id as GridRowId))
    setRows(newRows)
  }

  const getSelectedIndexes = () => {
    const reuslt: number[] = []
    const selectedRows = apiRef.current.getSelectedRows()
    selectedRows.forEach((_v, k) => {
      const idx = rows.findIndex(r => r.id === k)
      console.log(idx)
      if (idx >= 0) {
        reuslt.push(idx)
      }
    })
    return reuslt.sort()
  }

  const rowsUp = () => {
    const mock = {}
    const newRows = [mock, ...rows]
    const indexes = getSelectedIndexes()

    indexes.forEach(idx => {
      swapArrayItem(newRows, idx, idx + 1)
    })
    setRows(newRows.filter(r => r !== mock))
  }

  const rowsDown = () => {
    const mock = {}
    const newRows = [...rows, mock]
    const indexes = getSelectedIndexes().reverse()

    indexes.forEach(idx => {
      swapArrayItem(newRows, idx + 1, idx)
    })
    setRows(newRows.filter(r => r !== mock))
  }

  const rowsReverse = () => {
  
    const indexes = getSelectedIndexes()
    if(indexes.length > 1){
      const newRows = reverseArrayByIndexes(rows,indexes);
      setRows(newRows);
    }
  }

  const context = useContext(EditorContext)

  const columns = properties.map(p => ({
    field: p.name,
    headerName: p.title,
    editable: checkCanEdit(p),
    // type: 'string',
    sortable: false,
    renderEditCell: context.editCellRenderBuilder(p),
    renderCell: context.cellRenderBuilder(p),
    disableColumnMenu: true,
    flex: 1,
  }))

  const menu = !onlyEdit ? (
    <Stack direction="row" spacing={1}>
      {!disableAdd ? <CustomIcon icon={<AddIcon />} tooltip="添加新项" handler={addRow} /> : null}
      {!disableDelete ? <CustomIcon icon={<RemoveIcon />} tooltip="删除选中项" handler={deleteRow} /> : null}
      <CustomIcon icon={<ArrowUpwardIcon />} tooltip="上移选中项" handler={rowsUp} />
      <CustomIcon icon={<ArrowDownwardIcon />} tooltip="下移选中项" handler={rowsDown} />
      <CustomIcon icon={<SwapVertIcon />} tooltip="倒序选中项" handler={rowsReverse} />

    </Stack>
  ) : null

  return (
    <>
      {menu}
      {/* <Box sx={{ mt: 1,display:"flex", flexDirection:"column", flexShrink:1,flexBasis:"auto" }}> */}
      <DataGrid
        rows={rows}
        columns={columns}
        hideFooter={true}
        processRowUpdate={processRowUpdate}
        apiRef={apiRef}
        checkboxSelection={!onlyEdit}
        onCellEditStop={p => {
          console.log(p.field)
          setLastEditField(p.field)
        }}
        disableRowSelectionOnClick
      />
      {/* </Box> */}
    </>
  )
})


