/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import _ from 'lodash'
import { h, ref, reactive } from 'vue'
import { useI18n } from 'vue-i18n'
import { useRouter } from 'vue-router'
import { useAsyncState } from '@vueuse/core'
import { useTextCopy } from '../components/dag/use-text-copy'
import {
  batchCopyByCodes,
  batchDeleteByCodes,
  batchExportByCodes,
  deleteByCode,
  queryListPaging,
  release
} from '@/service/modules/process-definition'
import { offline, online } from '@/service/modules/schedules'
import TableAction from './components/table-action'
import styles from './index.module.scss'
import { NTag, NSpace, NIcon, NButton, NEllipsis, NTooltip } from 'naive-ui'
import { CopyOutlined, UnorderedListOutlined } from '@vicons/antd'
import ButtonLink from '@/components/button-link'
import {
  COLUMN_WIDTH_CONFIG,
  calculateTableWidth,
  DefaultTableWidth
} from '@/common/column-width-config'
import type { IDefinitionParam } from './types'
import type { Router } from 'vue-router'
import type { TableColumns, RowKey } from 'naive-ui/es/data-table/src/interface'
import { useDependencies } from '../../components/dependencies/use-dependencies'

export function useTable() {
  const { t } = useI18n()
  const router: Router = useRouter()
  const { copy } = useTextCopy()
  const { getDependentTaskLinks } = useDependencies()

  const variables = reactive({
    columns: [],
    tableWidth: DefaultTableWidth,
    checkedRowKeys: [] as Array<RowKey>,
    row: {},
    tableData: [],
    projectCode: ref(Number(router.currentRoute.value.params.projectCode)),
    page: ref(1),
    pageSize: ref(10),
    searchVal: ref(),
    totalPage: ref(1),
    timingType: ref('create'),
    timingState: ref('OFFLINE'),
    showRef: ref(false),
    startShowRef: ref(false),
    timingShowRef: ref(false),
    versionShowRef: ref(false),
    copyShowRef: ref(false),
    loadingRef: ref(false),
    setTimingDialogShowRef: ref(false),
    dependenciesData: ref({
      showRef: false,
      taskLinks: ref([]),
      required: ref(false),
      tip: ref(''),
      action: () => {}
    })
  })

  const createColumns = (variables: any) => {
    variables.columns = [
      {
        type: 'selection',
        className: 'btn-selected',
        ...COLUMN_WIDTH_CONFIG['selection']
      },
      {
        title: '#',
        key: 'id',
        ...COLUMN_WIDTH_CONFIG['index'],
        render: (row, index) => index + 1
      },
      {
        title: t('project.workflow.workflow_name'),
        key: 'name',
        className: 'workflow-name',
        ...COLUMN_WIDTH_CONFIG['name'],
        titleColSpan: 3,
        resizable: true,
        width: 300,
        minWidth: 300,
        maxWidth: 600,
        render: (row) =>
          h(
            NSpace,
            {
              justify: 'space-between',
              wrap: false,
              class: styles['workflow-name']
            },
            {
              default: () =>
                h(
                  ButtonLink,
                  {
                    onClick: () => {
                      const routeUrl = router.resolve({
                        name: 'workflow-definition-detail',
                        params: { code: row.code }
                      })
                      window.open(routeUrl.href, '_blank')
                    }
                  },
                  {
                    default: () =>
                      h(
                        NEllipsis,
                        {
                          style: 'max-width: 580px;line-height: 1.5'
                        },
                        () => row.name
                      )
                  }
                )
            }
          )
      },
      {
        title: 'Copy',
        key: 'copy',
        ...COLUMN_WIDTH_CONFIG['copy'],
        render: (row) =>
          h(NTooltip, null, {
            trigger: () =>
              h(
                NButton,
                {
                  quaternary: true,
                  circle: true,
                  type: 'info',
                  size: 'tiny',
                  onClick: () => void copy(row.name)
                },
                { icon: () => h(NIcon, { size: 16 }, () => h(CopyOutlined)) }
              ),
            default: () => t('project.workflow.copy_workflow_name')
          })
      },
      {
        title: 'Instances',
        key: 'instances',
        ...COLUMN_WIDTH_CONFIG['instances'],
        render: (row) =>
          h(NTooltip, null, {
            trigger: () =>
              h(
                NButton,
                {
                  quaternary: true,
                  circle: true,
                  type: 'info',
                  size: 'tiny',
                  onClick: () => {
                    void router.push({
                      name: 'workflow-instance-list',
                      query: { processDefineCode: row.code }
                    })
                  }
                },
                {
                  icon: () =>
                    h(NIcon, { size: 18 }, () => h(UnorderedListOutlined))
                }
              ),
            default: () => t('project.workflow.visit_workflow_instances')
          })
      },
      {
        title: t('project.workflow.status'),
        key: 'releaseState',
        ...COLUMN_WIDTH_CONFIG['state'],
        render: (row) =>
          row.releaseState === 'ONLINE'
            ? h(
                NTag,
                { type: 'success', size: 'small' },
                {
                  default: () => t('project.workflow.up_line')
                }
              )
            : h(
                NTag,
                { type: 'warning', size: 'small' },
                {
                  default: () => t('project.workflow.down_line')
                }
              )
      },
      {
        title: t('project.workflow.schedule_publish_status'),
        key: 'scheduleReleaseState',
        ...COLUMN_WIDTH_CONFIG['state'],
        render: (row) => {
          if (row.scheduleReleaseState === 'ONLINE') {
            return h(
              NTag,
              { type: 'success', size: 'small' },
              {
                default: () => t('project.workflow.up_line')
              }
            )
          } else if (row.scheduleReleaseState === 'OFFLINE') {
            return h(
              NTag,
              { type: 'warning', size: 'small' },
              {
                default: () => t('project.workflow.down_line')
              }
            )
          } else {
            return '-'
          }
        }
      },
      {
        title: t('project.workflow.create_time'),
        key: 'createTime',
        ...COLUMN_WIDTH_CONFIG['time']
      },
      {
        title: t('project.workflow.update_time'),
        key: 'updateTime',
        ...COLUMN_WIDTH_CONFIG['time']
      },
      {
        title: t('project.workflow.description'),
        key: 'description',
        ...COLUMN_WIDTH_CONFIG['note']
      },
      {
        title: t('project.workflow.create_user'),
        key: 'userName',
        ...COLUMN_WIDTH_CONFIG['userName']
      },
      {
        title: t('project.workflow.modify_user'),
        key: 'modifyBy',
        ...COLUMN_WIDTH_CONFIG['userName']
      },
      {
        title: t('project.workflow.operation'),
        key: 'operation',
        ...COLUMN_WIDTH_CONFIG['operation'](10),
        render: (row) =>
          h(TableAction, {
            row,
            onEditWorkflow: () => editWorkflow(row),
            onStartWorkflow: () => startWorkflow(row),
            onTimingWorkflow: () => timingWorkflow(row),
            onVersionWorkflow: () => versionWorkflow(row),
            onDeleteWorkflow: () => deleteWorkflow(row),
            onReleaseWorkflow: () => releaseWorkflow(row),
            onReleaseScheduler: () => releaseScheduler(row),
            onCopyWorkflow: () => copyWorkflow(row),
            onExportWorkflow: () => exportWorkflow(row),
            onGotoWorkflowTree: () => gotoWorkflowTree(row)
          })
      }
    ] as TableColumns<any>
    if (variables.tableWidth) {
      variables.tableWidth = calculateTableWidth(variables.columns)
    }
  }

  const editWorkflow = (row: any) => {
    variables.row = row
    router.push({
      name: 'workflow-definition-detail',
      params: { code: row.code }
    })
  }

  const startWorkflow = (row: any) => {
    variables.startShowRef = true
    variables.row = row
  }

  const timingWorkflow = (row: any) => {
    variables.timingShowRef = true
    if (row?.schedule) {
      variables.row = row.schedule
      variables.timingType = 'update'
      variables.timingState = row.scheduleReleaseState
    } else {
      variables.row = row
    }
  }

  const versionWorkflow = (row: any) => {
    variables.versionShowRef = true
    variables.row = row
  }

  const batchDeleteWorkflow = () => {
    const data = {
      codes: _.join(variables.checkedRowKeys, ',')
    }

    batchDeleteByCodes(data, variables.projectCode).then(() => {
      window.$message.success(t('project.workflow.success'))

      if (
        variables.tableData.length === variables.checkedRowKeys.length &&
        variables.page > 1
      ) {
        variables.page -= 1
      }

      variables.checkedRowKeys = []
      getTableData({
        pageSize: variables.pageSize,
        pageNo: variables.page,
        searchVal: variables.searchVal
      })
    })
  }

  const batchExportWorkflow = () => {
    const fileName = 'workflow_' + new Date().getTime()
    const data = {
      codes: _.join(variables.checkedRowKeys, ',')
    }

    batchExportByCodes(data, variables.projectCode).then((res: any) => {
      downloadBlob(res, fileName)
      window.$message.success(t('project.workflow.success'))
      variables.checkedRowKeys = []
    })
  }

  const batchCopyWorkflow = () => {}

  const confirmToOfflineWorkflow = () => {
    const row: any = variables.row
    const data = {
      name: row.name,
      releaseState: (row.releaseState === 'ONLINE' ? 'OFFLINE' : 'ONLINE') as
        | 'OFFLINE'
        | 'ONLINE'
    }
    if (data.releaseState === 'OFFLINE') {
      release(data, variables.projectCode, row.code).then(() => {
        getTableData({
          pageSize: variables.pageSize,
          pageNo: variables.page,
          searchVal: variables.searchVal
        })
        window.$message.success(t('project.workflow.success'))
      })
    }
    variables.dependenciesData.showRef = false
  }

  const confirmToOfflineScheduler = () => {
    const row: any = variables.row
    offline(variables.projectCode, row.schedule.id).then(() => {
      window.$message.success(t('project.workflow.success'))
      getTableData({
        pageSize: variables.pageSize,
        pageNo: variables.page,
        searchVal: variables.searchVal
      })
    })
    variables.dependenciesData.showRef = false
  }

  const releaseWorkflow = (row: any) => {
    const data = {
      name: row.name,
      releaseState: (row.releaseState === 'ONLINE' ? 'OFFLINE' : 'ONLINE') as
        | 'OFFLINE'
        | 'ONLINE'
    }
    variables.row = row
    if (data.releaseState === 'ONLINE') {
      release(data, variables.projectCode, row.code).then(() => {
        variables.setTimingDialogShowRef = true
        if (row?.schedule) {
          variables.row = row.schedule
          variables.timingType = 'update'
          variables.timingState = row.scheduleReleaseState
        }
        getTableData({
          pageSize: variables.pageSize,
          pageNo: variables.page,
          searchVal: variables.searchVal
        })
      })
    } else {
      getDependentTaskLinks(variables.projectCode, row.code).then(
        (res: any) => {
          if (res && res.length > 0) {
            variables.dependenciesData = {
              showRef: true,
              taskLinks: res,
              tip: t('project.workflow.warning_dependent_tasks_desc'),
              required: false,
              action: confirmToOfflineWorkflow
            }
          } else {
            release(data, variables.projectCode, row.code).then(() => {
              window.$message.success(t('project.workflow.success'))
              getTableData({
                pageSize: variables.pageSize,
                pageNo: variables.page,
                searchVal: variables.searchVal
              })
            })
          }
        }
      )
    }
  }

  const deleteWorkflow = (row: any) => {
    getDependentTaskLinks(variables.projectCode, row.code).then((res: any) => {
      if (res && res.length > 0) {
        variables.dependenciesData = {
          showRef: true,
          taskLinks: res,
          tip: t('project.workflow.delete_validate_dependent_tasks_desc'),
          required: true,
          action: () => {}
        }
      } else {
        deleteByCode(variables.projectCode, row.code).then(() => {
          window.$message.success(t('project.workflow.success'))
          getTableData({
            pageSize: variables.pageSize,
            pageNo: variables.page,
            searchVal: variables.searchVal
          })
        })
      }
    })
  }

  const releaseScheduler = (row: any) => {
    variables.row = row
    if (row.schedule) {
      if (row.schedule.releaseState === 'ONLINE') {
        getDependentTaskLinks(variables.projectCode, row.code).then(
          (res: any) => {
            if (res && res.length > 0) {
              variables.dependenciesData = {
                showRef: true,
                taskLinks: res,
                tip: t(
                  'project.workflow.warning_offline_scheduler_dependent_tasks_desc'
                ),
                required: false,
                action: confirmToOfflineScheduler
              }
            } else {
              offline(variables.projectCode, row.schedule.id).then(() => {
                window.$message.success(t('project.workflow.success'))
                getTableData({
                  pageSize: variables.pageSize,
                  pageNo: variables.page,
                  searchVal: variables.searchVal
                })
              })
            }
          }
        )
      } else {
        online(variables.projectCode, row.schedule.id).then(() => {
          window.$message.success(t('project.workflow.success'))
          getTableData({
            pageSize: variables.pageSize,
            pageNo: variables.page,
            searchVal: variables.searchVal
          })
        })
      }
    }
  }

  const copyWorkflow = (row: any) => {
    const data = {
      codes: String(row.code),
      targetProjectCode: variables.projectCode
    }
    batchCopyByCodes(data, variables.projectCode).then(() => {
      window.$message.success(t('project.workflow.success'))
      getTableData({
        pageSize: variables.pageSize,
        pageNo: variables.page,
        searchVal: variables.searchVal
      })
    })
  }

  const downloadBlob = (data: any, fileNameS = 'json') => {
    if (!data) {
      return
    }
    const blob = new Blob([data])
    const fileName = `${fileNameS}.json`
    if ('download' in document.createElement('a')) {
      // Not IE
      const url = window.URL.createObjectURL(blob)
      const link = document.createElement('a')
      link.style.display = 'none'
      link.href = url
      link.setAttribute('download', fileName)
      document.body.appendChild(link)
      link.click()
      document.body.removeChild(link) // remove element after downloading is complete.
      window.URL.revokeObjectURL(url) // release blob object
    } else {
      // IE 10+
      if (window.navigator.msSaveBlob) {
        window.navigator.msSaveBlob(blob, fileName)
      }
    }
  }

  const exportWorkflow = (row: any) => {
    const fileName = 'workflow_' + new Date().getTime()

    const data = {
      codes: String(row.code)
    }
    batchExportByCodes(data, variables.projectCode).then((res: any) => {
      downloadBlob(res, fileName)
    })
  }

  const gotoWorkflowTree = (row: any) => {
    router.push({
      name: 'workflow-definition-tree',
      params: { projectCode: variables.projectCode, definitionCode: row.code }
    })
  }

  const getTableData = (params: IDefinitionParam) => {
    if (variables.loadingRef) return
    variables.loadingRef = true
    const { state } = useAsyncState(
      queryListPaging({ ...params }, variables.projectCode).then((res: any) => {
        variables.totalPage = res.totalPage
        variables.tableData = res.totalList.map((item: any) => {
          return { ...item }
        })
        variables.loadingRef = false
      }),
      { total: 0, table: [] }
    )
    return state
  }

  return {
    variables,
    createColumns,
    getTableData,
    batchDeleteWorkflow,
    batchExportWorkflow,
    batchCopyWorkflow
  }
}
