<template>
  <el-card class="operation" shadow="hover">
    <template #header>
      <div class="operation-head">
        <el-icon><Stamp /></el-icon>
        <span>{{ state.resp?.activityDescriptor.name }}</span>
      </div>
    </template>

    <el-form v-if="canCopy">
      <el-form-item label="抄送">
        <el-checkbox-group v-model="state.copyOguList">
          <el-checkbox v-for="item in state.resp.copyAssigns" :key="item.fullPathName" :label="item.oguName" :value="item.fullPathName" :title="item.fullPathName" />
        </el-checkbox-group>
      </el-form-item>
    </el-form>

    <comments
      v-if="state.comments"
      :comments="state.comments"
      :can-edit="editable"
      :dept-show="deptCommentsEditable"
      @on-update-comments="onUpdateComments"
    />

    <div class="operation-body">
      <el-button
        v-if="canAgree"
        type="primary"
        plain
        :disabled="loading"
        :loading="loading && state.currOperation === 'agree'"
        @click="onAgree"
      >
        <el-icon><Right /></el-icon>
        <span>流转</span>
      </el-button>
      <el-button
        v-if="canSave"
        type="success"
        plain
        :disabled="loading"
        :loading="loading && state.currOperation === 'save'"
        @click="onSave"
      >
        <el-icon><DocumentChecked /></el-icon>
        <span>保存</span>
      </el-button>
      <el-button
        v-if="canBack"
        type="warning"
        plain
        :disabled="loading"
        :loading="loading && state.currOperation === 'back'"
        @click="onBack"
      >
        <el-icon><Back /></el-icon>
        <span>退回</span>
      </el-button>
      <el-button
        v-if="canRevoke"
        type="warning"
        plain
        :disabled="loading"
        :loading="loading && state.currOperation === 'revoke'"
        @click="onRevoke"
      >
        <el-icon><Back /></el-icon>
        <span>撤回</span>
      </el-button>
      <el-button
        v-if="canSuspend"
        type="warning"
        plain
        :disabled="loading"
        :loading="loading && state.currOperation === 'suspend'"
        @click="onSuspend"
      >
        <el-icon><Back /></el-icon>
        <span>挂起</span>
      </el-button>
      <el-button
        v-if="canReject"
        type="warning"
        plain
        :disabled="loading"
        :loading="loading && state.currOperation === 'reject'"
        @click="onReject"
      >
        <el-icon><Close /></el-icon>
        <span>驳回</span>
      </el-button>
      <el-button
        v-if="canDelete"
        type="warning"
        plain
        :disabled="loading"
        :loading="loading && state.currOperation === 'delete'"
        @click="onDelete"
      >
        <el-icon><Close /></el-icon>
        <span>删除</span>
      </el-button>
    </div>
    <operation-route
      :visible="state.routeVisible"
      :get-route-list="getRouteList"
      @on-close="onCloseRoute"
      @on-save="onSaveRoute"
    />
  </el-card>
</template>

<script setup lang="ts" generic="T extends BaseWorkflowForm">
import { computed, reactive, onMounted } from 'vue'
import { ElMessage, type FormInstance } from 'element-plus'

import { SuccessResultCode, type Result, type FrameUserInfo, type CreateRequestDto,
  type AgreeAutoRequestDto,
  type OperateRequestDto,
  type StartResponseDto,
  type BaseWorkflowForm,
  type OperationType,
  type RouteRequestDto,
  type RuntimeRouteNode,
  type AgreeRequestDto,
  type CommentsDto,
  type SaveRequestDto,
  type NextRouteData,
  type OperMode, useLoading, 
  type RuntimeOgu} from '@cacp/ui'

  import * as apis from '@/apis/workflow/engine'
import OperationRoute from './ProcessOperationRoute.vue'
import Comments from './ProcessComments.vue'

const props = defineProps<{
  contextPath: string
  mode: OperMode
  taskId?: string
  formId?: string
  processCode: string
  urlFormat: string
  range: number
  user: FrameUserInfo
  variables?: Record<string, unknown>
  nextBranchList: Array<RuntimeOgu>
  form?: T
  formRef?: FormInstance,
}>()

const emits = defineEmits<{
  (e: 'on-command', flag: OperationType): void
  (e: 'on-load', form: T, processCode: string, activityCode: string, editable: boolean): void
}>()

const { loading, setLoading } = useLoading()

const state = reactive<{
  currOperation?: OperationType
  resp?: Omit<StartResponseDto<T>, 'form' | 'comments'>
  comments?: CommentsDto
  routeVisible: boolean,
  copyOguList: Array<RuntimeOgu>
}>({
  routeVisible: false,
  copyOguList: []
})

const editable = computed(() => props.mode !== 'show' && !!state.resp?.activityDescriptor && !!state.resp?.canApprove)
const canAgree = computed(() => editable.value && !!state.resp?.canOperate.canAgree)
const canBack = computed(() => editable.value && !!state.resp?.canOperate.canBack)
const canSave = computed(() => editable.value && !!state.resp?.canOperate.canSave)
const canDelete = computed(() => editable.value && !!state.resp?.canOperate.canDelete)
const canSuspend = computed(() => editable.value && !!state.resp?.canOperate.canSuspend)
const canRevoke = computed(() => !!state.resp?.canOperate.canRevoke)
const canReject = computed(() => editable.value && !!state.resp?.canOperate.canReject)
const canRoute = computed(() => editable.value && !!state.resp?.activityDescriptor.routeOptional)
const canCopy = computed(() => editable.value && !!state.resp?.canCopy)
const deptCommentsEditable = computed(() => editable.value && !!state.resp?.activityDescriptor.options.operation_deptComments && props.form?.processId !== state.resp?.task.processId)

onMounted(async () => {
  setLoading(true)

  let res: Result<StartResponseDto<T>>
  if (props.mode === 'oper') {
    res = await apis.start<T>(props.contextPath, props.taskId!, props.formId!)
  } else if (props.mode === 'create') {
    const req: CreateRequestDto = {
      urlFormat: props.urlFormat!,
      processCode: props.processCode!,
      range: props.range!
    }
    res = await apis.createStart<T>(props.contextPath, req)
  } else {
    res = await apis.show<T>(props.contextPath, props.taskId!, props.formId!)
  }
  
  if (res.code === SuccessResultCode && res.data) {
    state.resp = {
      task: res.data.task,
      processCode: res.data.processCode,
      activityDescriptor: res.data.activityDescriptor,
      canApprove: res.data.canApprove,
      canOperate: res.data.canOperate,
      canCopy: res.data.canCopy,
      copyNodeCode: res.data.copyNodeCode,
      copyAssigns: res.data.copyAssigns
    }
    state.copyOguList = res.data.copyAssigns
    
    state.comments = res.data.comments
    emits('on-load', res.data.form, res.data.processCode, res.data.activityDescriptor.code, editable.value)
  }

  setLoading(false)
})

async function onAgree() {
  state.currOperation = 'agree'

  const valid = await props.formRef!.validate()
  if (!valid) {
    return
  }

  if (canRoute.value) {
    state.routeVisible = true
  } else {
    state.copyOguList.forEach(a => a.copyFlag = true)
    const req: AgreeAutoRequestDto<T> = {
      taskId: state.resp!.task.taskId,
      comments: state.comments,
      copyNodeCode: state.resp!.copyNodeCode,
      copyOguList: state.copyOguList,
      nextBranchList: props.nextBranchList,
      form: props.form!,
      variables: props.variables
    }

    setLoading(true)
    const res: Result<boolean> = await apis.autoAgree(props.contextPath, req)
    setLoading(false)

    if (res.code !== SuccessResultCode) {
      ElMessage.error({
        message: res.message,
        showClose: true
      })

      return
    }

    emits('on-command', state.currOperation)
  }
}

async function onSave() {
  state.currOperation = 'save'

  const valid = await props.formRef!.validate()
  if (!valid) {
    return
  }

  const req: SaveRequestDto<T> = {
    taskId: state.resp!.task.taskId,
    comments: state.comments,
    form: props.form!
  }

  setLoading(true)
  const res: Result<boolean> = await apis.save(props.contextPath, req)
  setLoading(false)

  if (res.code !== SuccessResultCode) {
    ElMessage.error({
      message: res.message,
      showClose: true
    })

    return
  }

  emits('on-command', state.currOperation)
}

async function onBack() {
  state.currOperation = 'back'

  const valid = await props.formRef!.validate()
  if (!valid) {
    return
  }

  const req: OperateRequestDto<T> = {
    taskId: state.resp!.task.taskId,
    comments: state.comments,
    form: props.form!
  }

  setLoading(true)
  const res: Result<boolean> = await apis.back(props.contextPath, req)
  setLoading(false)

  if (res.code !== SuccessResultCode) {
    ElMessage.error({
      message: res.message,
      showClose: true
    })

    return
  }

  emits('on-command', state.currOperation)
}

async function onRevoke() {
  state.currOperation = 'revoke'

  setLoading(true)
  const res: Result<boolean> = await apis.revoke(props.contextPath, state.resp!.task.taskId, state.resp!.task.bizId)
  setLoading(false)

  if (res.code !== SuccessResultCode) {
    ElMessage.error({
      message: res.message,
      showClose: true
    })

    return
  }

  emits('on-command', state.currOperation)
}

async function onReject() {
  state.currOperation = 'reject'

  const valid = await props.formRef!.validate()
  if (!valid) {
    return
  }

  const req: OperateRequestDto<T> = {
    taskId: state.resp!.task.taskId,
    comments: state.comments,
    form: props.form!
  }

  setLoading(true)
  const res: Result<boolean> = await apis.reject(props.contextPath, req)
  setLoading(false)

  if (res.code !== SuccessResultCode) {
    ElMessage.error({
      message: res.message,
      showClose: true
    })

    return
  }

  emits('on-command', state.currOperation)
}

async function onSuspend() {
  state.currOperation = 'suspend'

  const valid = await props.formRef!.validate()
  if (!valid) {
    return
  }

  const req: OperateRequestDto<T> = {
    taskId: state.resp!.task.taskId,
    comments: state.comments,
    form: props.form!
  }

  setLoading(true)
  const res: Result<boolean> = await apis.suspend(props.contextPath, req)
  setLoading(false)

  if (res.code !== SuccessResultCode) {
    ElMessage.error({
      message: res.message,
      showClose: true
    })

    return
  }

  emits('on-command', state.currOperation)
}

async function onDelete() {
  state.currOperation = 'delete'

  setLoading(true)
  const res: Result<boolean> = await apis.remove(props.contextPath, state.resp!.task.taskId, state.resp!.task.bizId)
  setLoading(false)

  if (res.code !== SuccessResultCode) {
    ElMessage.error({
      message: res.message,
      showClose: true
    })

    return
  }

  emits('on-command', state.currOperation)
}

async function getRouteList(): Promise<Array<RuntimeRouteNode>> {
  const valid = await props.formRef!.validate()
  if (!valid) {
    return []
  }

  const req: RouteRequestDto = {
    taskId: state.resp!.task.taskId,
    variables: props.variables
  }

  const res = await apis.route(props.contextPath, req)
  if (res.code !== SuccessResultCode) {
    ElMessage.error({
      message: res.message,
      showClose: true
    })

    return []
  }

  return res.data ?? []
}

function onCloseRoute() {
  state.routeVisible = false
}

async function onSaveRoute(routeData: NextRouteData) {
  state.currOperation = 'agree'

  state.copyOguList.forEach(a => a.copyFlag = true)
  const req: AgreeRequestDto<T> = {
    taskId: state.resp!.task.taskId,
    comments: state.comments,
    routeNodeCode: routeData.nextNodeCode,
    routeOguList: props.nextBranchList && props.nextBranchList.length > 0 ? props.nextBranchList : routeData.nextOguList,
    copyNodeCode: state.resp!.copyNodeCode,
    copyOguList: state.copyOguList,
    form: props.form!,
    variables: props.variables
  }

  setLoading(true)
  const res: Result<boolean> = await apis.agree(props.contextPath, req)
  setLoading(false)

  if (res.code !== SuccessResultCode) {
    ElMessage.error({
      message: res.message,
      showClose: true
    })

    return
  }

  emits('on-command', state.currOperation)
}

function onUpdateComments(comments: CommentsDto) {
  state.comments = comments
}
</script>
