<template>
  <div>
    <Form :layout="'vertical'" ref="formRef" :model="modelRef">
      <FormItem :name="['message', 'messageType']" label="动作类型" :rules="[{ required: true, message: '请选择动作类型' }]">
        <TopCard :typeList="TypeList" v-model:value="modelRef.message.messageType" @change="onMessageTypeChange" />
      </FormItem>
      <template v-if="deviceMessageType === 'INVOKE_FUNCTION'">
        <FormItem :name="['message', 'functionId']" label="功能调用" :rules="[{ required: true, message: '请选择功能' }]">
          <Select showSearch placeholder="请选择功能" v-model:value="modelRef.message.functionId" @change="functionSelect">
            <SelectOption v-for="item in metadata?.functions || []" :value="item?.id" :key="item?.id" :label="item?.name">
              {{ item?.name }}
            </SelectOption>
          </Select>
        </FormItem>
        <FormItem
          v-if="modelRef.message.functionId && functions.length"
          :name="['message', 'inputs']"
          :rules="functionRules"
        >
          <EditTable :functions="functions" v-model:value="modelRef.message.inputs" :builtInList="builtInList" />
        </FormItem>
      </template>
      <template v-else-if="deviceMessageType === 'READ_PROPERTY'">
        <FormItem
          :name="['message', 'properties']"
          label="读取属性"
          :rules="[{ required: true, message: '请选择读取属性' }]"
        >
          <Select
            showSearch
            placeholder="请选择属性"
            v-model:value="modelRef.message.properties[0]"
            @change="propertySelect"
          >
            <SelectOption
              v-for="item in (metadata?.properties || []).filter((i) => i?.expands?.type?.includes('read')) || []"
              :value="item?.id"
              :key="item?.id"
              :label="item?.name"
            >
              {{ item?.name }}
            </SelectOption>
          </Select>
        </FormItem>
      </template>
      <template v-else-if="deviceMessageType === 'WRITE_PROPERTY'">
        <WriteProperty
          ref="writeFormRef"
          v-model:value="modelRef.message.properties"
          :metadata="metadata"
          :builtInList="builtInList"
          @change="onWriteChange"
        />
      </template>
    </Form>
  </div>
</template>

<script lang="ts" setup>
  import { getImage } from '@jdlinker/utils';
  import TopCard from '../device/TopCard.vue';
  import { detail } from '../../../../../../../api/device/instance';
  import EditTable from './EditTable.vue';
  import WriteProperty from './WriteProperty.vue';
  import { storeToRefs } from 'pinia';
  import { getParams } from '../../../util';
  import { useSceneStore } from '@jdlinker/func';
  import { ref, reactive, computed, watch, unref } from 'vue';
  import { FormItem, Select, SelectOption, Form } from 'linker-ui-components';

  const sceneStore = useSceneStore();
  const { data } = storeToRefs(sceneStore);

  const TypeList = [
    {
      label: '功能调用',
      value: 'INVOKE_FUNCTION',
      image: getImage('/scene/invoke-function.png'),
      tip: ''
    },
    {
      label: '读取属性',
      value: 'READ_PROPERTY',
      image: getImage('/scene/read-property.png'),
      tip: ''
    },
    {
      label: '设置属性',
      value: 'WRITE_PROPERTY',
      image: getImage('/scene/write-property.png'),
      tip: ''
    }
  ];

  const props = defineProps({
    values: {
      type: Object,
      default: () => {}
    },
    name: {
      type: Number,
      default: 0
    },
    thenName: {
      type: Number,
      default: 0
    },
    branchesName: {
      type: Number,
      default: 0
    },
    productDetail: {
      type: Object,
      default: () => {}
    }
  });

  const emit = defineEmits(['change']);

  const formRef = ref();

  const modelRef = reactive({
    message: {
      messageType: 'INVOKE_FUNCTION',
      functionId: undefined,
      properties: undefined,
      inputs: []
    },
    propertiesValue: ''
  });

  const writeFormRef = ref();

  const functionSelect = (val: any, options?: any) => {
    modelRef.message.inputs = [];
    emit('change', {
      propertiesName: options?.label,
      propertiesValue: modelRef.propertiesValue
    });
  };

  const propertySelect = (val: any, options?: any) => {
    emit('change', {
      propertiesName: options?.label,
      propertiesValue: modelRef.propertiesValue
    });
  };

  const functionRules = [
    {
      validator(_: string, value: any) {
        const arr = functions.value.filter((i: any) => {
          return i?.expands?.required;
        });
        if (arr.length) {
          if (!value?.length) {
            return Promise.reject('请输入功能值');
          } else {
            const hasValue = value?.find((item: { name: string; value: any }) => item.value === undefined);
            if (hasValue) {
              const functionItem = arr?.find((item: any) => item.id === hasValue.name);
              return Promise.reject(functionItem?.name ? `请输入${functionItem.name}值` : '请输入功能值');
            }
          }
        }
        return Promise.resolve();
      },
      trigger: ['change', 'blur']
    }
  ];

  const metadata = ref<{
    functions: any[];
    properties: any[];
  }>({
    functions: [],
    properties: []
  });

  const deviceMessageType = computed(() => {
    return modelRef.message.messageType;
  });

  const builtInList = ref<any[]>([]);

  const functions = computed(() => {
    const _item = (metadata.value?.functions || []).find((item: any) => {
      return modelRef.message?.functionId === item.id;
    });
    return _item?.inputs || [];
  });

  const _property = computed(() => {
    const _item = (metadata.value?.properties || []).find((item: any) => {
      if (deviceMessageType.value === 'WRITE_PROPERTY') {
        return Object.keys(modelRef.message.properties || {})?.[0] === item.id;
      }
      return modelRef.message?.properties?.[0] === item.id;
    });
    return _item;
  });

  const _function = computed(() => {
    const _item = (metadata.value?.functions || []).find((item: any) => {
      return modelRef.message?.functionId === item.id;
    });
    return _item;
  });

  const queryBuiltIn = async () => {
    const _params = {
      branch: props.thenName,
      branchGroup: props.branchesName,
      action: props.name - 1
    };
    const _data = await getParams(_params, unref(data));
    builtInList.value = _data;
  };

  const onMessageTypeChange = (val: string) => {
    const flag = ['WRITE_PROPERTY', 'INVOKE_FUNCTION'].includes(val);
    modelRef.message = {
      messageType: val,
      functionId: undefined,
      properties: (flag ? undefined : []) as any,
      inputs: []
    };
    if (flag) {
      queryBuiltIn();
    }
  };

  watch(
    () => props.productDetail,
    (newVal) => {
      if (newVal?.id) {
        console.log(props.values);
        if (props.values?.selector === 'fixed' && props.values?.selectorValues?.length === 1) {
          const id = props.values?.selectorValues?.[0]?.value;
          if (id) {
            detail(id).then((resp) => {
              if (resp.code === 200) {
                metadata.value = JSON.parse(resp.result?.metadata || '{}');
                console.log(metadata.value, resp.result?.metadata);
              }
            });
          }
        } else {
          metadata.value = JSON.parse(newVal?.metadata || '{}');
        }
      }
    },
    { immediate: true }
  );

  watch(
    () => props.values?.message,
    (newVal) => {
      if (newVal?.messageType) {
        modelRef.message = newVal;
        if (['WRITE_PROPERTY', 'INVOKE_FUNCTION'].includes(newVal.messageType)) {
          queryBuiltIn();
        }
      }
    },
    { immediate: true }
  );

  const onWriteChange = (val: string, optionColumn: string[]) => {
    modelRef.propertiesValue = val;
    emit(
      'change',
      {
        propertiesName: deviceMessageType.value === 'INVOKE_FUNCTION' ? _function.value?.name : _property.value?.name,
        propertiesValue: modelRef.propertiesValue
      },
      optionColumn
    );
  };

  const onFormSave = () => {
    return new Promise((resolve, reject) => {
      formRef.value
        .validate()
        .then(async (_data: any) => {
          if (writeFormRef.value) {
            const _val = await writeFormRef.value?.onSave();
            if (!_val) {
              reject(false);
            }
          }
          resolve({
            message: {
              ...modelRef.message,
              ..._data.message
            }
          });
          // emit('change', {
          //     propertiesName:
          //         deviceMessageType.value === 'INVOKE_FUNCTION'
          //             ? _function.value?.name
          //             : _property.value?.name,
          //     propertiesValue: modelRef.propertiesValue,
          // });
        })
        .catch((err: any) => {
          reject(err);
        });
    });
  };

  defineExpose({ onFormSave });
</script>
