/*
 * 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 {
  defineComponent,
  PropType,
  ref,
  computed,
  onMounted,
  watch,
  getCurrentInstance
} from 'vue'
import Modal from '@/components/modal'
import { useI18n } from 'vue-i18n'
import {
  NForm,
  NFormItem,
  NInput,
  NSelect,
  NSwitch,
  NInputNumber,
  NDynamicInput,
  NCheckbox
} from 'naive-ui'
import { queryTenantList } from '@/service/modules/tenants'
import { useRoute } from 'vue-router'
import { verifyName } from '@/service/modules/process-definition'
import './x6-style.scss'
import { positiveIntegerRegex } from '@/utils/regex'
import type { SaveForm, WorkflowDefinition, WorkflowInstance } from './types'

const props = {
  visible: {
    type: Boolean as PropType<boolean>,
    default: false
  },
  // If this prop is passed, it means from definition detail
  definition: {
    type: Object as PropType<WorkflowDefinition>,
    default: undefined
  },
  instance: {
    type: Object as PropType<WorkflowInstance>,
    default: undefined
  }
}

interface Tenant {
  tenantCode: string
  id: number
}

export default defineComponent({
  name: 'dag-save-modal',
  props,
  emits: ['update:show', 'save'],
  setup(props, context) {
    const route = useRoute()
    const { t } = useI18n()

    const projectCode = Number(route.params.projectCode)
    const tenants = ref<Tenant[]>([])
    const tenantsDropdown = computed(() => {
      if (tenants.value) {
        return tenants.value
          .map((t) => ({
            label: t.tenantCode,
            value: t.tenantCode
          }))
          .concat({ label: 'default', value: 'default' })
      }
      return []
    })
    onMounted(() => {
      queryTenantList().then((res: any) => {
        tenants.value = res
      })
    })

    const formValue = ref<SaveForm>({
      name: '',
      description: '',
      tenantCode: 'default',
      executionType: 'PARALLEL',
      timeoutFlag: false,
      timeout: 0,
      globalParams: [],
      release: false,
      sync: false
    })
    const formRef = ref()

    const rule = {
      name: {
        required: true,
        message: t('project.dag.dag_name_empty')
      },
      timeout: {
        validator() {
          if (
            formValue.value.timeoutFlag &&
            !positiveIntegerRegex.test(String(formValue.value.timeout))
          ) {
            return new Error(t('project.dag.positive_integer'))
          }
        }
      },
      globalParams: {
        validator() {
          const props = new Set()

          const keys = formValue.value.globalParams.map((item) => item.key)
          const keysSet = new Set(keys)
          if (keysSet.size !== keys.length) {
            return new Error(t('project.dag.prop_repeat'))
          }

          for (const param of formValue.value.globalParams) {
            const prop = param.value
            if (!prop) {
              return new Error(t('project.dag.prop_empty'))
            }

            props.add(prop)
          }
        }
      }
    }
    const onSubmit = () => {
      formRef.value.validate(async (valid: any) => {
        if (!valid) {
          const params = {
            name: formValue.value.name,
            code: props.definition?.processDefinition.code
          } as { name: string; code?: number }
          if (
            props.definition?.processDefinition.name !== formValue.value.name
          ) {
            verifyName(params, projectCode).then(() =>
              context.emit('save', formValue.value)
            )
          } else {
            context.emit('save', formValue.value)
          }
        }
      })
    }
    const onCancel = () => {
      context.emit('update:show', false)
    }

    const updateModalData = () => {
      const process = props.definition?.processDefinition
      if (process) {
        formValue.value.name = process.name
        formValue.value.description = process.description
        formValue.value.tenantCode = process.tenantCode || 'default'
        formValue.value.executionType = process.executionType || 'PARALLEL'
        if (process.timeout && process.timeout > 0) {
          formValue.value.timeoutFlag = true
          formValue.value.timeout = process.timeout
        }
        formValue.value.globalParams = process.globalParamList.map((param) => ({
          key: param.prop,
          value: param.value
        }))
      }
    }

    const trim = getCurrentInstance()?.appContext.config.globalProperties.trim

    onMounted(() => updateModalData())

    watch(
      () => props.definition?.processDefinition,
      () => updateModalData()
    )

    return () => (
      <Modal
        show={props.visible}
        title={t('project.dag.basic_info')}
        onConfirm={onSubmit}
        onCancel={onCancel}
        autoFocus={false}
      >
        <NForm model={formValue.value} rules={rule} ref={formRef}>
          <NFormItem label={t('project.dag.workflow_name')} path='name'>
            <NInput
              allowInput={trim}
              v-model:value={formValue.value.name}
              class='input-name'
            />
          </NFormItem>
          <NFormItem label={t('project.dag.description')} path='description'>
            <NInput
              allowInput={trim}
              type='textarea'
              v-model:value={formValue.value.description}
              class='input-description'
            />
          </NFormItem>
          <NFormItem label={t('project.dag.tenant')} path='tenantCode'>
            <NSelect
              options={tenantsDropdown.value}
              v-model:value={formValue.value.tenantCode}
              class='btn-select-tenant-code'
            />
          </NFormItem>
          <NFormItem label={t('project.dag.timeout_alert')} path='timeoutFlag'>
            <NSwitch v-model:value={formValue.value.timeoutFlag} />
          </NFormItem>
          {formValue.value.timeoutFlag && (
            <NFormItem showLabel={false} path='timeout'>
              <NInputNumber
                v-model:value={formValue.value.timeout}
                show-button={false}
                min={0}
                v-slots={{
                  suffix: () => t('project.dag.minute')
                }}
              />
            </NFormItem>
          )}
          {!props.instance && (
            <NFormItem
              label={t('project.dag.process_execute_type')}
              path='executionType'
            >
              <NSelect
                options={[
                  { value: 'PARALLEL', label: t('project.dag.parallel') },
                  { value: 'SERIAL_WAIT', label: t('project.dag.serial_wait') },
                  {
                    value: 'SERIAL_DISCARD',
                    label: t('project.dag.serial_discard')
                  },
                  {
                    value: 'SERIAL_PRIORITY',
                    label: t('project.dag.serial_priority')
                  }
                ]}
                v-model:value={formValue.value.executionType}
              />
            </NFormItem>
          )}
          <NFormItem
            label={t('project.dag.global_variables')}
            path='globalParams'
          >
            <NDynamicInput
              v-model:value={formValue.value.globalParams}
              preset='pair'
              key-placeholder={t('project.dag.key')}
              value-placeholder={t('project.dag.value')}
              class='input-global-params'
            />
          </NFormItem>
          {props.definition && !props.instance && (
            <NFormItem path='timeoutFlag' showLabel={false}>
              <NCheckbox v-model:checked={formValue.value.release}>
                {t('project.dag.online_directly')}
              </NCheckbox>
            </NFormItem>
          )}
          {props.instance && (
            <NFormItem path='sync' showLabel={false}>
              <NCheckbox v-model:checked={formValue.value.sync}>
                {t('project.dag.update_directly')}
              </NCheckbox>
            </NFormItem>
          )}
        </NForm>
      </Modal>
    )
  }
})
