<script lang="ts" setup>
import { BasicModal, useModalInner } from '@/components/Modal'
import type { FormSchema, FormSchemaInner, Rule } from '@/components/Form'
import { BasicForm, useForm } from '@/components/Form'
import { CloudCommandType } from '@/api/device-manage/device/types'
import { sendCommandToDevice, sendMessageToDevice } from '@/api/device-manage/device/cloud-command'
import CodeEditor from '@/components/CodeEditor/src/CodeEditor.vue'
import { getAllModelAttributes } from '@/api/product/model'
import { getDeviceTopicList } from '@/api/device-manage/device'
import { ModelAttributeDataTypesEnum, type SimpleAttribute } from '@/api/product/types'
import { useMessage } from '@/hooks/web/useMessage'

const emit = defineEmits(['register', 'success'])

const [registerForm, { updateSchema, resetSchema, validate, setFieldsValue, clearValidate }] = useForm({
  schemas: [],
  labelWidth: 100,
  baseColProps: { span: 24 },
  showActionButtonGroup: false,
  actionColOptions: { span: 23 },
})

let productId: string
let deviceId: string
let commandType: CloudCommandType
const CommandAndAttributeSchemas: FormSchema[] = [
  {
    field: 'itemId',
    label: '选择属性',
    required: true,
    component: 'ApiSelect',
    componentProps: {
      api: () => getAllModelAttributes(productId!, commandType),
      valueField: 'id',
      labelField: 'name',
      allowClear: false,
      onChange(_, option: SimpleAttribute & { label: string }) { // label is SimpleAttribute.name
        if (!option)
          return

        const { dataType, label, dataSpecs, modelId } = option
        setFieldsValue({ modelId, value: undefined })
        // avoid non-null check
        clearValidate()

        let schema: Partial<FormSchemaInner> = {}
        if (dataType === ModelAttributeDataTypesEnum.Bool) {
          schema = {
            rules: [], // remove rules cache
            component: 'RadioGroup',
            componentProps: {
              options: [
                { label: dataSpecs.falseDesc, value: 0 },
                { label: dataSpecs.trueDesc, value: 1 },
              ],
            },
          }
        }
        else {
          let rules: Rule[] = []
          switch (dataType) {
            case ModelAttributeDataTypesEnum.Text:
              rules = [{ max: dataSpecs.maxLength, message: `限制最大长度为 ${dataSpecs.maxLength}` }]
              break
            case ModelAttributeDataTypesEnum.Float:
            case ModelAttributeDataTypesEnum.Int32:
              rules = [
                { type: 'number', min: +dataSpecs.min, max: +dataSpecs.max, message: `数值范围为: ${dataSpecs.min}-${dataSpecs.max}` },
              ]
              break
            default: {
              const _exhaustiveCheck: never = dataType
              return _exhaustiveCheck
            }
          }

          schema = {
            rules,
            // if it isn't text, then it's a float or int32
            component: dataType === ModelAttributeDataTypesEnum.Text ? 'InputTextArea' : 'InputNumber',
            componentProps: dataType !== ModelAttributeDataTypesEnum.Text
              ? {
                  precision: dataType === ModelAttributeDataTypesEnum.Float ? dataSpecs.scale : 0,
                }
              : { rows: 3 },
          }
        }
        updateSchema({
          label,
          field: 'value',
          ifShow: true,
          ...schema,
        })
      },
    },
  },
  {
    field: 'value',
    fields: ['modelId'],
    required: true,
    component: 'Input',
    ifShow: false,
  },
]
const MessageSchemas: FormSchema[] = [
  {
    field: 'topic',
    label: 'Topic',
    required: true,
    component: 'ApiSelect',
    componentProps: {
      api: async () => (await getDeviceTopicList({ deviceId, current: 1, size: 500 })).records,
      valueField: 'topic',
      labelField: 'topic',
    },
  },
  {
    field: 'message',
    label: '指令内容',
    rules: [
      {
        async validator(_, value) {
          try {
            const code = JSON.stringify(JSON.parse(value))
            if (code === '{}')
            // eslint-disable-next-line unicorn/error-message
              throw new Error()
          }
          catch {
            // eslint-disable-next-line prefer-promise-reject-errors
            return Promise.reject('指令内容必须是 JSON 格式, 且不能为空')
          }
        },
        required: true,
      },
    ],
    slot: 'Message',
    helpMessage: '指令内容必须是 JSON 格式',
    defaultValue: {},
    componentProps: {
      rows: 10,
    },
  },
]
const [register, { closeModal, setModalProps }] = useModalInner((params: { type: CloudCommandType, productId: string, deviceId: string }) => {
  productId = params.productId
  deviceId = params.deviceId
  commandType = params.type
  resetSchema(commandType === CloudCommandType.Message ? MessageSchemas : CommandAndAttributeSchemas)
})

async function handleSubmit() {
  try {
    const values = await validate<any>()
    setModalProps({ confirmLoading: true })
    values.deviceId = deviceId
    const isSendMessage = commandType === CloudCommandType.Message
    await (isSendMessage ? sendMessageToDevice(values) : sendCommandToDevice(values))
    useMessage().createMessage.success('下发成功')
    emit('success')
    closeModal()
  }
  catch {}
  finally {
    setModalProps({ confirmLoading: false })
  }
}
</script>

<template>
  <BasicModal
    v-bind="$attrs"
    :min-height="100"
    @register="register"
    @ok="handleSubmit"
  >
    <BasicForm @register="registerForm">
      <template #Message="{ model, field }">
        <div h="200px" border="1px solid gray-200" w-full overflow-hidden rounded>
          <CodeEditor v-model:value="model[field]" />
        </div>
      </template>
    </BasicForm>
  </BasicModal>
</template>