import { useState, useEffect, memo, useMemo, useCallback, useContext } from 'react'
import { Button, Form, Input, Popconfirm, Timeline } from 'antd'
import {
  CheckSquareOutlined,
  EditOutlined,
  SaveOutlined,
  PlusOutlined,
  CloseCircleOutlined,
  DeleteOutlined
} from '@ant-design/icons'

import { IdWellContext } from '@asb/context'
import LoaderPortal from '@components/LoaderPortal'
import { invokeWebApiWrapperAsync } from '@components/factory'
import { hasPermission } from '@utils/permissions'
import { formatDate } from '@utils'
import { MeasureService } from '@api'

import { View } from './View'

import '@styles/index.css'
import '@styles/measure.css'

const createEditingColumns = (cols, renderDelegate) =>
  cols.map(col => ({ render: renderDelegate, ...col }))

const disabled = !hasPermission('Measure.edit')

export const MeasureTable = memo(({ group, updateMeasuresFunc, additionalButtons }) => {
  const [showLoader, setShowLoader] = useState(false)
  const [displayedValues, setDisplayedValues] = useState({})
  const [editingColumns, setEditingColumns] = useState(group.columns)
  const [isTableEditing, setIsTableEditing] = useState(false)
  const [editingActionName, setEditingActionName] = useState('')

  const idWell = useContext(IdWellContext)

  const [measuresForm] = Form.useForm()

  const data = useMemo(() => group?.values?.length > 0 ? group.values : [group?.defaultValue], [group?.defaultValue, group?.values])

  useEffect(() => setDisplayedValues(data.at(-1)), [data])

  useEffect(() => {
    const switchableColumns = createEditingColumns(
      group.columns,
      isTableEditing ? () => <Input className={'w-100 measure-input'} /> : null
    )

    if(editingActionName === 'edit')
      measuresForm.setFieldsValue(displayedValues?.data)
    else if(editingActionName === 'add')
      measuresForm.resetFields()

    setEditingColumns(switchableColumns)
  }, [isTableEditing, group.columns, editingActionName, displayedValues?.data, measuresForm])

  const markMeasuresAsDeleted = async () => await invokeWebApiWrapperAsync(
    async () => {
      await MeasureService.markAsDelete(idWell, displayedValues.id)
      updateMeasuresFunc()
    },
    setShowLoader,
    `Не удалось удалить запись ${displayedValues.id} для скважины "${idWell}"`,
    'Удаление записи для скважины'
  )
  const editingDisabled = useMemo(() => disabled || !!displayedValues?.isDefaultData, [displayedValues?.isDefaultData])
  const deleteDisabled = useMemo(() => !hasPermission('Measure.delete') || !!displayedValues?.isDefaultData, [displayedValues?.isDefaultData])

  const editTable = useCallback((action) => {
    setEditingActionName(action)
    setIsTableEditing(true)
  }, [])

  const handleSubmitMeasuresForm = useCallback(async (formData) => await invokeWebApiWrapperAsync(
    async () => {
      measuresForm.validateFields()

      const measureParams = {
        idWell: idWell,
        idCategory: group.idCategory,
        timestamp: new Date().toISOString(),
        data: formData
      }

      if(editingActionName === 'add') {
        await MeasureService.insert(idWell, measureParams)
      } else if (editingActionName === 'edit') {
        measureParams.id = displayedValues.id
        measureParams.timestamp = displayedValues.timestamp
        await MeasureService.update(idWell, measureParams)
      }

      setIsTableEditing(false)
      updateMeasuresFunc()
    },
    setShowLoader,
    `Не удалось добавить/изменить запись для скаважины "${idWell}"`,
    'Добавление/изменение записи по скважине'
  ), [displayedValues?.id, displayedValues?.timestamp, editingActionName, group.idCategory, idWell, measuresForm, updateMeasuresFunc])

  return (
    <>
      &nbsp;<h2>{group.title}</h2>&nbsp;
      <div className={'d-flex'}>
        <div className={'flex-direction-column'}>
          <div className={'measure-buttons-container'}>
            <div className={'w-300px mt-8px d-flex'} style={{ alignItems: 'stretch' }}>
              { isTableEditing ? (
                <>
                  <Button key={'confirm'} className={'flex-1'} onClick={() => measuresForm.submit()}>
                    <SaveOutlined />
                  </Button>
                  <Button key={'decline'} className={'flex-1'} onClick={() => setIsTableEditing(false)}>
                    <CloseCircleOutlined />
                  </Button>
                </>
              ) : (
                <>
                  <Button key={'add'} className={'flex-1'} onClick={() => editTable('add')} disabled={disabled}>
                    <PlusOutlined />
                  </Button>
                  <Button key={'edit'} className={'flex-1'} onClick={() => editTable('edit')} disabled={editingDisabled}>
                    <EditOutlined />
                  </Button>
                  <Popconfirm style={{ flex: '1' }} title={'Удалить данные?'} onConfirm={markMeasuresAsDeleted} disabled={deleteDisabled}>
                    <Button key={'delete'} onClick={() => setEditingActionName('delete')} disabled={deleteDisabled}>
                      <DeleteOutlined style={{ margin:'auto 28px' }}/>
                    </Button>
                  </Popconfirm>
                </>
              )}
              {additionalButtons?.(isTableEditing)}
            </div>
          </div>

          <div className={'measure-dates mt-20px'}>
            <Timeline className={'mt-12px ml-10px'}>
              {data.map((item, index) => (
                <Timeline.Item
                  key={index}
                  className={'measure-button'}
                  onClick={() => setDisplayedValues(item)}
                  dot={item?.id === displayedValues?.id && (
                    <CheckSquareOutlined className={'timeline-clock-icon'} />
                  )}
                >
                  <span className={item?.id === displayedValues?.id ? 'selected-timeline' : undefined}>
                    {formatDate(item.timestamp) ?? 'Нет данных'}
                  </span>
                </Timeline.Item>
              ))}
            </Timeline>
          </div>
        </div>
        <div className={'w-100'}>
          <LoaderPortal show={showLoader}>
            <Form form={measuresForm} onFinish={handleSubmitMeasuresForm}>
              <View item={displayedValues?.data ?? {}} columns={editingColumns} />
            </Form>
          </LoaderPortal>
        </div>
      </div>
    </>
  )
})

export default MeasureTable
