import { Button, Notification, toast } from '@/components/ui'
import { GridDto, UiCommandButtonPositionTypeEnum, WorkflowDto } from '@/proxy/form/models'
import { dynamicFetch } from '@/services/form.service'
import { useLocalization } from '@/utils/hooks/useLocalization'
import { usePermission } from '@/utils/hooks/usePermission'
import { DataGridTypes } from 'devextreme-react/data-grid'
import { ToolbarItem } from 'devextreme/ui/data_grid_types'
import { useEffect, useState } from 'react'
import { useDialogContext } from '../shared/DialogContext'
import { usePWA } from '@/utils/hooks/usePWA'
import { layoutTypes, ListViewLayoutType } from '../admin/listForm/edit/types'
import { useStoreState } from '@/store'
import { workflowService } from '@/services/workflow.service'

type ToolbarModalData = {
  open: boolean
  content?: JSX.Element
}

// https://js.devexpress.com/Documentation/ApiReference/UI_Components/dxDataGrid/Configuration/toolbar/
// item.name > Accepted Values: 'addRowButton', 'applyFilterButton', 'columnChooserButton', 'exportButton', 'groupPanel', 'revertButton', 'saveButton', 'searchPanel'
const useToolbar = ({
  gridDto,
  listFormCode,
  getSelectedRowKeys,
  getSelectedRowsData,
  refreshData,
  getFilter,
  layout,
  expandAll,
  collapseAll,
}: {
  gridDto?: GridDto
  listFormCode: string
  getSelectedRowKeys: () => unknown[] | Promise<unknown[]>
  getSelectedRowsData: () => any
  refreshData: () => void
  getFilter: () => void
  layout: ListViewLayoutType | string
  expandAll?: () => void
  collapseAll?: () => void
}): {
  toolbarData: ToolbarItem[]
  toolbarModalData: ToolbarModalData | undefined
  setToolbarModalData: (data: ToolbarModalData | undefined) => void
} => {
  const dialog: any = useDialogContext()
  const { translate } = useLocalization()
  const { checkPermission } = usePermission()
  const isPwaMode = usePWA()
  const currentUser = useStoreState((state) => state.auth.user)

  const [toolbarData, setToolbarData] = useState<ToolbarItem[]>([])
  const [toolbarModalData, setToolbarModalData] = useState<ToolbarModalData>()
  const grdOpt = gridDto?.gridOptions

  function getToolbarData() {
    const items: ToolbarItem[] = []

    if (!gridDto || !grdOpt) {
      setToolbarData(items)
      return
    }

    // Add searchPanel
    if (grdOpt.searchPanelDto?.visible) {
      items.push({
        locateInMenu: 'auto',
        showText: 'inMenu',
        name: 'searchPanel',
      })
    }

    // Add InsertNewRecord button
    if (grdOpt.editingOptionDto?.allowAdding && checkPermission(grdOpt.permissionDto?.c)) {
      if (grdOpt.editingOptionDto?.addPageUrl) {
        items.push({
          widget: 'dxButton',
          showText: 'always',
          name: 'addRowButton',
          location: 'after',
          options: {
            text: translate('::ListForms.ListForm.AddNewRecord'),
            hint: translate('::ListForms.ListForm.AddNewRecord'),
            onClick() {
              window.open(grdOpt.editingOptionDto?.addPageUrl, isPwaMode ? '_self' : '_blank')
            },
          },
        })
      } else {
        items.push({
          locateInMenu: 'auto',
          showText: 'always',
          name: 'addRowButton',
          location: 'after',
          options: {
            text: translate('::ListForms.ListForm.AddNewRecord'),
            hint: translate('::ListForms.ListForm.AddNewRecord'),
          },
        })
      }
    }

    items.push({
      widget: 'dxButton',
      name: 'refreshButton',
      options: {
        icon: 'refresh',
        onClick: refreshData,
        text: translate('::ListForms.ListForm.Refresh'),
      },
      location: 'after',
    })

    const workflowOptions = grdOpt.workflowDto
    const approvalCriteria =
      workflowOptions?.criteria?.filter((item) => item.kind === 'Approval') ?? []
    if (
      workflowOptions?.approvalStatusFieldName &&
      approvalCriteria.length > 0 &&
      grdOpt.updateServiceAddress
    ) {
      items.push({
        widget: 'dxButton',
        name: 'workflowStart',
        location: 'after',
        options: {
          icon: 'play',
          text: 'Workflow Start',
          hint: 'Workflow Start',
          visible: true,
          disabled: true,
          onClick: async () => {
            const keys = (await Promise.resolve(getSelectedRowKeys() as any)) as unknown[]
            if (!keys?.length) {
              toast.push(
                <Notification type="warning" duration={2000}>
                  {translate('::ListForms.ListForm.SelectRecord')}
                </Notification>,
                { placement: 'top-end' },
              )
              return
            }

            const selectedRows = ((await Promise.resolve(getSelectedRowsData() as any)) ||
              []) as Record<string, unknown>[]
            if (
              selectedRows.length === 0 ||
              !selectedRows.every((row) => isWorkflowNotStarted(row, workflowOptions))
            ) {
              toast.push(
                <Notification type="warning" duration={2500}>
                  {translate('::WorkflowAlreadyStarted')}
                </Notification>,
                { placement: 'top-end' },
              )
              return
            }

            try {
              await workflowService.startWorkflow(listFormCode, keys)
              refreshData()
            } catch (error: any) {
              toast.push(
                <Notification type="danger" duration={3000}>
                  {error?.response?.data?.error?.message ||
                    error?.response?.data?.message ||
                    error?.message ||
                    'Workflow baslatilamadi.'}
                </Notification>,
                { placement: 'top-end' },
              )
            }
          },
        },
      })

      approvalCriteria.forEach((criteria) => {
        items.push({
          widget: 'dxButton',
          name: `workflowApproval_${criteria.id}`,
          location: 'after',
          options: {
            icon: 'check',
            text: criteria.title,
            hint: criteria.title,
            visible: true,
            disabled: true,
            onClick: async () => {
              const keys = (await Promise.resolve(getSelectedRowKeys() as any)) as unknown[]
              if (!keys?.length) {
                toast.push(
                  <Notification type="warning" duration={2000}>
                    {translate('::ListForms.ListForm.SelectRecord')}
                  </Notification>,
                  { placement: 'top-end' },
                )
                return
              }

              const selectedRows = ((await Promise.resolve(getSelectedRowsData() as any)) ||
                []) as Record<string, unknown>[]
              const activeRows = selectedRows.filter((row) =>
                isWorkflowApprovalCriteriaActive(
                  row,
                  workflowOptions,
                  criteria.title,
                  getCurrentUserWorkflowIdentities(currentUser),
                ),
              )

              if (activeRows.length !== selectedRows.length) {
                toast.push(
                  <Notification type="warning" duration={2500}>
                    {translate('::SeciliKayitBekliyor')}
                  </Notification>,
                  { placement: 'top-end' },
                )
                return
              }

              setToolbarModalData({
                open: true,
                content: (
                  <>
                    <WorkflowApprovalDecisionDialog
                      criteriaTitle={criteria.title}
                      keys={keys}
                      listFormCode={listFormCode}
                      criteriaId={criteria.id}
                      onCancel={() => setToolbarModalData(undefined)}
                      onCompleted={() => {
                        refreshData()
                        setToolbarModalData(undefined)
                      }}
                    />
                  </>
                ),
              })
            },
          },
        })
      })
    }

    // Add Expand All button for TreeList
    if (layout === layoutTypes.tree && grdOpt.treeOptionDto?.parentIdExpr) {
      items.push({
        widget: 'dxButton',
        name: 'expandAllButton',
        options: {
          icon: 'plus',
          text: translate('::ListForms.ListFormEdit.ExpandAll'),
          onClick: expandAll,
        },
        location: 'after',
      })

      // Add Collapse All button for TreeList
      items.push({
        widget: 'dxButton',
        name: 'collapseAllButton',
        options: {
          icon: 'minus',
          text: translate('::ListForms.ListFormEdit.CollapseAll'),
          onClick: collapseAll,
        },
        location: 'after',
      })
    }

    // field chooser panel
    if (grdOpt.columnOptionDto?.columnChooserEnabled) {
      items.push({
        locateInMenu: 'auto',
        showText: 'inMenu',
        name: 'columnChooserButton',
        options: {
          hint: translate('::ListForms.ListForm.ColumnChooser'),
        },
      })
    }

    // Add group panel
    if (grdOpt.groupPanelDto?.visible) {
      items.push({
        locateInMenu: 'auto',
        showText: 'inMenu',
        name: 'groupPanel',
      })
    }

    // Add DeleteSelectedRecords button
    // coklu silme icin
    if (grdOpt.editingOptionDto?.allowDeleting && checkPermission(grdOpt.permissionDto?.d)) {
      items.push({
        location: 'after',
        widget: 'dxButton',
        locateInMenu: 'auto',
        showText: 'inMenu',
        name: 'deleteSelectedRecords',
        options: {
          text: translate('::ListForms.ListForm.DeleteSelectedRecords'),
          icon: 'trash',
          visible: false,
          async onClick() {
            if (!grdOpt.deleteServiceAddress) {
              return
            }

            const selectedKeys = await Promise.resolve(getSelectedRowKeys())
            const keys = Array.isArray(selectedKeys) ? [...selectedKeys] : []

            if (!keys.length) {
              toast.push(
                <Notification type="warning" duration={2000}>
                  {translate('::ListForms.ListForm.SelectRecord')}
                </Notification>,
                { placement: 'top-end' },
              )
              return
            }

            setToolbarModalData({
              open: true,
              content: (
                <>
                  <h5 className="mb-4">
                    {translate('::ListForms.ListForm.DeleteSelectedRecords')}
                  </h5>

                  <p>
                    {translate('::SeciliKayitlarSilmekIstiyormusunuz', {
                      0: keys.length,
                    })}
                  </p>

                  <div className="text-right mt-6">
                    <Button
                      className="ltr:mr-2 rtl:ml-2"
                      variant="plain"
                      onClick={() => setToolbarModalData(undefined)}
                    >
                      {translate('::Cancel')}
                    </Button>
                    <Button
                      variant="solid"
                      onClick={() => {
                        dynamicFetch(grdOpt.deleteServiceAddress!, 'POST', null, {
                          keys,
                          listFormCode,
                        })
                          .then(() => {
                            refreshData()
                            setToolbarModalData(undefined)
                          })
                          .catch((error: any) => {
                            toast.push(
                              <Notification type="danger" duration={3000}>
                                {error?.response?.data?.error?.message ||
                                  error?.response?.data?.message ||
                                  error?.message ||
                                  translate('::SilmeIslemiBasarisiz')}
                              </Notification>,
                              { placement: 'top-end' },
                            )
                          })
                      }}
                    >
                      {translate('::Delete')}
                    </Button>
                  </div>
                </>
              ),
            })
          },
        },
      })

      // Add DeleteAllRecords button
      // butun kayitlari (filtreli) icin
      if (grdOpt.editingOptionDto?.allowAllDeleting) {
        const buttonDeleteAll: DataGridTypes.ToolbarItem = {
          location: 'after',
          widget: 'dxButton',
          name: 'deleteAllRecords',
          options: {
            text: translate('::ListForms.ListForm.DeleteAllRecords'),
            hint: translate('::ListForms.ListForm.DeleteAllRecords'),
            icon: 'trash',
            visible: true,
            onClick() {
              const parameters = {
                listFormCode,
                filter: JSON.stringify(getFilter()),
                onlyTotalCountQuery: true,
                createDeleteQuery: false,
              }

              dynamicFetch('list-form-select/select', 'GET', parameters).then((r: any) => {
                setToolbarModalData({
                  open: true,
                  content: (
                    <>
                      <h5 className="mb-4">{translate('::ListForms.ListForm.DeleteAllRecords')}</h5>

                      <p>
                        {translate('::TumKayitlariSilmekIstiyormusunuz', {
                          0: r.data.totalCount,
                        })}
                      </p>

                      <div className="text-right mt-6">
                        <Button
                          className="ltr:mr-2 rtl:ml-2"
                          variant="plain"
                          onClick={() => setToolbarModalData(undefined)}
                        >
                          Cancel
                        </Button>
                        <Button
                          variant="solid"
                          onClick={() => {
                            //delete parameters.onlyTotalCountQuery
                            parameters.createDeleteQuery = true // tumunu silme islemi parametresi > set
                            dynamicFetch('list-form-select/select', 'GET', parameters).then(() => {
                              toast.push(
                                <Notification type="success" duration={2000}>
                                  {translate('::TumKayitlarSilindi')}
                                </Notification>,
                                {
                                  placement: 'top-end',
                                },
                              )

                              refreshData()

                              setToolbarModalData(undefined)
                            })
                          }}
                        >
                          Save
                        </Button>
                      </div>
                    </>
                  ),
                })
              })
            },
          },
        }
        items.push(buttonDeleteAll)
      }
    }

    // #region Toolbar icin kullanici tanimli dinamik butonlari ekler
    for (let i = 0; i < grdOpt.commandColumnDto.length; i++) {
      const action = grdOpt.commandColumnDto[i]

      // action.buttonPosition == 1 ise Toolbar butonudur, burada sadece Toolbar butonunu eklenir
      if (action.buttonPosition !== UiCommandButtonPositionTypeEnum.Toolbar) {
        continue
      }

      if (checkPermission(action.authName)) {
        const buttonCustom: DataGridTypes.ToolbarItem = {
          location: 'after',
          widget: 'dxButton',
          name: action.hint,
          options: {
            hint: translate('::' + action.hint),
            text: translate('::' + action.text),
            icon: action.icon,
            visible: true,
            onClick(e: any) {
              if (typeof e.event?.preventDefault === 'function') {
                e?.event?.preventDefault()
              }
              if (action.url) {
                let url = action.url
                // griddeki secili satirlari al
                const selectedRowsData = getSelectedRowsData()
                // constsa her bir secili satir icin donguye gir
                for (let i = 0; i < selectedRowsData.length; i++) {
                  // secili satirin objesine ait property verilerini al
                  const keys = Object.keys(selectedRowsData[i])
                  // secili satirin her bir property si icin donguye gir
                  for (let j = 0; j < keys.length; j++) {
                    // secili satirin j indexine sahip property ismini al
                    const fieldName = keys[j]
                    // secili satirin j indexine sahip property isminin degerini al
                    const fieldValue = selectedRowsData[i][fieldName]
                    // url icerisindeki {PropertyName} seklindeki anahtarlari secili satirdaki uyusan propertyler ile degistir
                    url = url.replace(`@${fieldName}`, fieldValue)
                  }
                  break // Url cagirmak icin kullanilacak parametreler sadece secili olan ilk satirdan alinir!
                }
                window.open(url, isPwaMode ? '_self' : action.urlTarget)
              } else if (action.dialogName) {
                if (action.dialogParameters) {
                  var dynamicMap = JSON.parse(action.dialogParameters)
                  for (const [key, value] of Object.entries<string>(dynamicMap)) {
                    dynamicMap[key] = value.startsWith('@')
                      ? e.row.data[value.replace('@', '')]
                      : value
                  }
                  dialog.setConfig({
                    component: action.dialogName,
                    props: dynamicMap,
                  })
                }
              } else if (action.onClick) {
                eval(action.onClick)
              }
            },
          },
        }
        items.push(buttonCustom)
      }
    }
    // #endregion

    // batch editing icin kaydet ve geri al butonu
    if (
      grdOpt.editingOptionDto?.allowUpdating &&
      grdOpt.editingOptionDto?.mode == 'batch' &&
      checkPermission(grdOpt.permissionDto?.u)
    ) {
      items.push({
        locateInMenu: 'auto',
        showText: 'inMenu',
        name: 'saveButton',
        options: { hint: translate('::App.SaveChanges') },
      })

      items.push({
        locateInMenu: 'auto',
        showText: 'inMenu',
        name: 'revertButton',
        options: { hint: translate('::App.UndoChanges') },
      })
    }
    // #endregion

    setToolbarData(items)
  }

  useEffect(() => {
    if (!gridDto && !listFormCode) return

    getToolbarData()
  }, [gridDto, listFormCode, currentUser])

  return {
    toolbarData,
    toolbarModalData,
    setToolbarModalData,
  }
}

function isWorkflowApprovalCriteriaActive(
  row: Record<string, unknown>,
  workflowOptions: WorkflowDto,
  criteriaTitle: string,
  currentUserIdentities: string[] = [],
) {
  if (!workflowOptions.approvalStatusFieldName || !criteriaTitle) {
    return false
  }

  const statusMatches =
    normalizeWorkflowValue(row?.[workflowOptions.approvalStatusFieldName]) ===
    normalizeWorkflowValue(criteriaTitle)

  if (!statusMatches) {
    return false
  }

  if (!workflowOptions.approvalUserFieldName) {
    return true
  }

  const approver = normalizeWorkflowValue(row?.[workflowOptions.approvalUserFieldName])
  return currentUserIdentities.some((identity) => normalizeWorkflowValue(identity) === approver)
}

function normalizeWorkflowValue(value: unknown) {
  return String(value ?? '')
    .trim()
    .toLocaleLowerCase('tr-TR')
}

function isWorkflowNotStarted(row: Record<string, unknown>, workflowOptions: WorkflowDto) {
  return normalizeWorkflowValue(row?.[workflowOptions.approvalStatusFieldName]) === ''
}

function getCurrentUserWorkflowIdentities(currentUser?: {
  userName?: string
  email?: string
  name?: string
}) {
  return [currentUser?.email, currentUser?.userName, currentUser?.name].filter(Boolean) as string[]
}

export function updateWorkflowApprovalToolbarItems(
  component: any,
  workflowOptions: WorkflowDto | undefined,
  selectedRowsData: Record<string, unknown>[] = [],
  currentUser?: {
    userName?: string
    email?: string
    name?: string
  },
) {
  const approvalCriteria =
    workflowOptions?.criteria?.filter((item) => item.kind === 'Approval') ?? []
  if (!component || !workflowOptions?.approvalStatusFieldName || !approvalCriteria.length) {
    return
  }

  const toolbarOptions = component.option('toolbar')
  if (!toolbarOptions?.items || !Array.isArray(toolbarOptions.items)) {
    return
  }

  const workflowStartItemIndex = toolbarOptions.items
    .map((item: any) => item.name)
    .indexOf('workflowStart')

  if (workflowStartItemIndex >= 0) {
    const startEnabled =
      selectedRowsData.length > 0 &&
      selectedRowsData.every((row) => isWorkflowNotStarted(row, workflowOptions))
    const startOptionPath = `toolbar.items[${workflowStartItemIndex}].options.disabled`
    const nextStartDisabled = !startEnabled
    if (component.option(startOptionPath) !== nextStartDisabled) {
      component.option(startOptionPath, nextStartDisabled)
    }
  }

  const currentUserIdentities = getCurrentUserWorkflowIdentities(currentUser)

  approvalCriteria.forEach((criteria) => {
    const toolbarItemIndex = toolbarOptions.items
      .map((item: any) => item.name)
      .indexOf(`workflowApproval_${criteria.id}`)

    if (toolbarItemIndex < 0) {
      return
    }

    const enabled =
      selectedRowsData.length > 0 &&
      selectedRowsData.every((row) =>
        isWorkflowApprovalCriteriaActive(
          row,
          workflowOptions,
          criteria.title,
          currentUserIdentities,
        ),
      )

    const optionPath = `toolbar.items[${toolbarItemIndex}].options.disabled`
    const nextDisabled = !enabled
    if (component.option(optionPath) !== nextDisabled) {
      component.option(optionPath, nextDisabled)
    }
  })
}

function WorkflowApprovalDecisionDialog({
  criteriaTitle,
  keys,
  listFormCode,
  criteriaId,
  onCancel,
  onCompleted,
}: {
  criteriaTitle: string
  keys: unknown[]
  listFormCode: string
  criteriaId: string
  onCancel: () => void
  onCompleted: () => void
}) {
  const { translate } = useLocalization()
  const [note, setNote] = useState('')
  const [submitting, setSubmitting] = useState(false)

  const decide = async (approved: boolean) => {
    setSubmitting(true)
    try {
      await Promise.all(
        keys.map((key) =>
          workflowService.decideWorkflow(listFormCode, [key], approved, note, criteriaId),
        ),
      )
      onCompleted()
    } catch (error: any) {
      toast.push(
        <Notification type="danger" duration={3000}>
          {error?.response?.data?.error?.message ||
            error?.response?.data?.message ||
            error?.message ||
            'Workflow karari verilemedi.'}
        </Notification>,
        { placement: 'top-end' },
      )
    } finally {
      setSubmitting(false)
    }
  }

  return (
    <>
      <h5 className="mb-4">{criteriaTitle}</h5>
      <p className="mb-4">
        {translate('::App.Listform.ListformField.WorkflowDecisionMessage', {
          0: keys.length,
        })}
      </p>
      <textarea
        className="input input-textarea mb-4 min-h-[96px] w-full resize-y"
        rows={4}
        value={note}
        autoFocus
        placeholder={translate('::App.Listform.ListformField.ApprovalComment')}
        onChange={(event) => setNote(event.target.value)}
      />
      <div className="text-right mt-6">
        <Button
          className="ltr:mr-2 rtl:ml-2"
          variant="plain"
          disabled={submitting}
          onClick={onCancel}
        >
          {translate('::Cancel')}
        </Button>
        <Button className="ltr:mr-2 rtl:ml-2" disabled={submitting} onClick={() => decide(false)}>
          {translate('::App.Listform.ListformField.Rejecter')}
        </Button>
        <Button variant="solid" disabled={submitting} onClick={() => decide(true)}>
          {translate('::App.Listform.ListformField.Approver')}
        </Button>
      </div>
    </>
  )
}

export { useToolbar }
