<script setup lang="ts">
import { computed, onMounted, reactive, ref } from 'vue';
import { message } from 'ant-design-vue';

import { useDictData } from '@/hooks/dict-data';
import { useRequest } from '@/hooks/request';
import { useViewVisible } from '@/hooks/view-visible';
import { t } from '@/i18n';
import { addProtocolParam, updateProtocolParam } from '@/api';
import { DictCode } from '@/constants';

import type { FormInstance } from 'ant-design-vue';
import type { DefaultOptionType, SelectValue } from 'ant-design-vue/es/select';
import type { FormRules, ProtocolParamInfo } from '@/types';

interface Props {
  protocolId?: number;
  paramId?: number;
  isModbusRtuProtocol?: boolean;
  isModbusTcpProtocol?: boolean;
  isS7Protocol?: boolean;
}

const props = defineProps<Props>();

const emit = defineEmits<{
  refreshList: [];
}>();

const { visible, showView, hideView } = useViewVisible();
const { handleRequest } = useRequest();
const { dictData: readWriteTypes, getDictData: getReadWriteTypes } = useDictData(DictCode.ReadWriteType);
const { dictData: registerTypes, getDictData: getRegisterTypes } = useDictData(DictCode.RegisterType);
const { dictData: wordLength, getDictData: getWordLength } = useDictData(DictCode.WordLength);
const { dictData: parsingTypes, getDictData: getParsingTypes } = useDictData(DictCode.ParsingType);
const { dictData: writeFuncCode, getDictData: getWriteFuncCode } = useDictData(DictCode.WriteFuncCode);
const { dictData: readFuncCode, getDictData: getReadFuncCode } = useDictData(DictCode.ReadFuncCode);
const { dictData: isHighFreqParam, getDictData: getIsHighFreqParam } = useDictData(DictCode.IsHighFreqParam);

const customParamsForm = reactive<Partial<ProtocolParamInfo>>({
  gatewayParamName: '',
  gatewayParamCode: '',
  unit: '',
  module: '',
  readWriteType: undefined,
  readWriteTypeCode: undefined,
  parsingType: undefined,
  parsingTypeCode: undefined,
  writeFuncCode: undefined,
  readFuncCode: undefined,
  addrLength: undefined,
  addrNumber: '',
  registerAddr: '',
  registerType: undefined,
  registerTypeCode: undefined,
  wordLength: undefined,
  wordLengthCode: undefined,
  quantity: undefined,
  coefficient: undefined,
  isHighFreqParam: undefined,
  isHighFreqParamCode: undefined,
  readCalcFormula: '',
  writeCalcFormula: '',
  decimalPlace: undefined,
});

const rules = computed<FormRules<ProtocolParamInfo>>(() => {
  return {
    gatewayParamName: [
      {
        required: true,
        message: t('common.plzEnter', { name: t('setupProtocol.protocolParamFields.gatewayParamName') }),
        trigger: 'blur',
      },
    ],
    gatewayParamCode: [
      {
        required: true,
        message: t('common.plzEnter', { name: t('setupProtocol.protocolParamFields.gatewayParamCode') }),
        trigger: 'blur',
      },
    ],
    readWriteType: [
      {
        required: true,
        message: t('common.plzSelect', { name: t('setupProtocol.protocolParamFields.readWriteType') }),
        trigger: 'blur',
      },
    ],
    parsingType: [
      {
        required: true,
        message: t('common.plzSelect', { name: t('setupProtocol.protocolParamFields.parsingType') }),
        trigger: 'blur',
      },
    ],
    addrLength: [
      {
        required: true,
        message: t('common.plzEnter', { name: t('setupProtocol.protocolParamFields.addressLength') }),
        trigger: 'blur',
      },
    ],
    addrNumber: [
      {
        required: true,
        message: t('common.plzEnter', { name: t('setupProtocol.protocolParamFields.addrNumber') }),
        trigger: 'blur',
      },
    ],
    registerType: [
      {
        required: true,
        message: t('common.plzSelect', { name: t('setupProtocol.protocolParamFields.registerType') }),
        trigger: 'blur',
      },
    ],
    registerAddr: [
      {
        required: true,
        message: t('common.plzEnter', { name: t('setupProtocol.protocolParamFields.registerAddress') }),
        trigger: 'blur',
      },
    ],
    wordLength: [
      {
        required: true,
        message: t('common.plzSelect', { name: t('setupProtocol.protocolParamFields.wordLength') }),
        trigger: 'blur',
      },
    ],
  };
});

const isModbusProtocol = computed(() => {
  return props.isModbusRtuProtocol || props.isModbusTcpProtocol;
});

const isAddParams = ref(true);

const modalTitle = computed(() => {
  return isAddParams.value ? t('setupProtocol.addCustomParams') : t('setupProtocol.updateCustomParams');
});

const setIsAddParams = (isAdd: boolean) => {
  isAddParams.value = isAdd;
};

const setParamsForm = (params: ProtocolParamInfo) => {
  Object.keys(customParamsForm).forEach((key) => {
    const value = params[key];

    if (value !== undefined && value !== null) {
      customParamsForm[key] = value;
    }
  });
};

onMounted(() => {
  handleRequest(async () => {
    await getReadWriteTypes();
    await getRegisterTypes();
    await getWordLength();
    await getParsingTypes();
    await getWriteFuncCode();
    await getReadFuncCode();
    await getIsHighFreqParam();
  });
});

const handleReadWriteTypeChange = (_value: SelectValue, option: DefaultOptionType) => {
  customParamsForm.readWriteTypeCode = option.key;
};

const handleRegisterTypeChange = (_value: SelectValue, option: DefaultOptionType) => {
  customParamsForm.registerTypeCode = option.key;
};

const handleWordLengthChange = (_value: SelectValue, option: DefaultOptionType) => {
  customParamsForm.wordLengthCode = option.key;
};

const handleParsingTypeChange = (_value: SelectValue, option: DefaultOptionType) => {
  customParamsForm.parsingTypeCode = option.key;
};

const handleIsHighFreqParamChange = (_value: SelectValue, option: DefaultOptionType) => {
  customParamsForm.isHighFreqParamCode = option.key;
};

const formRef = ref<FormInstance>();

const handleOk = () => {
  formRef.value
    ?.validate()
    .then(() => {
      handleRequest(async () => {
        if (isAddParams.value) {
          await addProtocolParam({
            baseInfoId: props.protocolId,
            ...customParamsForm,
          });

          message.success(t('setupProtocol.addCustomParamsSuccessful'));
        } else {
          await updateProtocolParam({
            ...customParamsForm,
            id: props.paramId,
          });

          message.success(t('setupProtocol.updateCustomParamsSuccessful'));
        }

        hideView();
        emit('refreshList');
      });
    })
    .catch((err) => {
      console.error(err);
    });
};

const handleClose = () => {
  formRef.value?.resetFields();
};

defineExpose({
  showView,
  hideView,
  setIsAddParams,
  setParamsForm,
});
</script>

<template>
  <AModal v-model:open="visible" :title="modalTitle" :width="920" centered :after-close="handleClose" @ok="handleOk">
    <AForm ref="formRef" :model="customParamsForm" :rules="rules" layout="vertical">
      <ARow :gutter="30">
        <ACol :span="8">
          <AFormItem :label="$t('setupProtocol.protocolParamFields.gatewayParamName')" name="gatewayParamName">
            <AInput
              v-model:value="customParamsForm.gatewayParamName"
              class="protocol-input"
              :placeholder="$t('common.plzEnter')"
            />
          </AFormItem>
        </ACol>
        <ACol :span="8">
          <AFormItem :label="$t('setupProtocol.protocolParamFields.gatewayParamCode')" name="gatewayParamCode">
            <AInput
              v-model:value="customParamsForm.gatewayParamCode"
              class="protocol-input"
              :placeholder="$t('common.plzEnter')"
            />
          </AFormItem>
        </ACol>
        <ACol :span="8">
          <AFormItem :label="$t('setupProtocol.protocolParamFields.unit')" name="unit">
            <AInput v-model:value="customParamsForm.unit" class="protocol-input" :placeholder="$t('common.plzEnter')" />
          </AFormItem>
        </ACol>
        <ACol :span="8">
          <AFormItem :label="$t('setupProtocol.protocolParamFields.module')" name="module">
            <AInput
              v-model:value="customParamsForm.module"
              class="protocol-input"
              :placeholder="$t('common.plzEnter')"
            />
          </AFormItem>
        </ACol>
        <ACol :span="8">
          <AFormItem :label="$t('setupProtocol.protocolParamFields.readWriteType')" name="readWriteType">
            <ASelect
              v-model:value="customParamsForm.readWriteType"
              class="protocol-input"
              :placeholder="$t('common.plzSelect')"
              @change="handleReadWriteTypeChange"
            >
              <ASelectOption v-for="item in readWriteTypes" :key="item.dictEngValue" :value="item.dictValue">
                {{ item.dictValue }}
              </ASelectOption>
            </ASelect>
          </AFormItem>
        </ACol>
        <ACol :span="8">
          <AFormItem :label="$t('setupProtocol.protocolParamFields.parsingType')" name="parsingType">
            <ASelect
              v-model:value="customParamsForm.parsingType"
              class="protocol-input"
              :placeholder="$t('common.plzSelect')"
              @change="handleParsingTypeChange"
            >
              <ASelectOption v-for="item in parsingTypes" :key="item.dictEngValue" :value="item.dictValue">
                {{ item.dictValue }}
              </ASelectOption>
            </ASelect>
          </AFormItem>
        </ACol>
        <ACol v-if="isModbusProtocol" :span="8">
          <AFormItem :label="$t('setupProtocol.protocolParamFields.writeFunctionCode')" name="writeFuncCode">
            <ASelect
              v-model:value="customParamsForm.writeFuncCode"
              class="protocol-input"
              :placeholder="$t('common.plzSelect')"
            >
              <ASelectOption v-for="item in writeFuncCode" :key="item.dictEngValue" :value="item.dictValue">
                {{ item.dictValue }}
              </ASelectOption>
            </ASelect>
          </AFormItem>
        </ACol>
        <ACol v-if="isModbusProtocol" :span="8">
          <AFormItem :label="$t('setupProtocol.protocolParamFields.readFunctionCode')" name="readFuncCode">
            <ASelect
              v-model:value="customParamsForm.readFuncCode"
              class="protocol-input"
              :placeholder="$t('common.plzSelect')"
            >
              <ASelectOption v-for="item in readFuncCode" :key="item.dictEngValue" :value="item.dictValue">
                {{ item.dictValue }}
              </ASelectOption>
            </ASelect>
          </AFormItem>
        </ACol>
        <ACol v-if="isModbusProtocol" :span="8">
          <AFormItem :label="$t('setupProtocol.protocolParamFields.addressLength')" name="addrLength">
            <AInputNumber
              v-model:value="customParamsForm.addrLength"
              class="protocol-input"
              :placeholder="$t('common.plzEnter')"
              :min="0"
              :precision="0"
            />
          </AFormItem>
        </ACol>
        <ACol v-if="isS7Protocol" :span="8">
          <AFormItem :label="$t('setupProtocol.protocolParamFields.addrNumber')" name="addrNumber">
            <AInput
              v-model:value="customParamsForm.addrNumber"
              class="protocol-input"
              :placeholder="$t('common.plzEnter')"
            />
          </AFormItem>
        </ACol>
        <ACol v-if="isS7Protocol" :span="8">
          <AFormItem :label="$t('setupProtocol.protocolParamFields.registerType')" name="registerType">
            <ASelect
              v-model:value="customParamsForm.registerType"
              class="protocol-input"
              :placeholder="$t('common.plzSelect')"
              @change="handleRegisterTypeChange"
            >
              <ASelectOption v-for="item in registerTypes" :key="item.dictEngValue" :value="item.dictValue">
                {{ item.dictValue }}
              </ASelectOption>
            </ASelect>
          </AFormItem>
        </ACol>
        <ACol :span="8">
          <AFormItem :label="$t('setupProtocol.protocolParamFields.registerAddress')" name="registerAddr">
            <AInput
              v-model:value="customParamsForm.registerAddr"
              class="protocol-input"
              :placeholder="$t('common.plzEnter')"
            />
          </AFormItem>
        </ACol>
        <ACol v-if="isS7Protocol" :span="8">
          <AFormItem :label="$t('setupProtocol.protocolParamFields.wordLength')" name="wordLength">
            <ASelect
              v-model:value="customParamsForm.wordLength"
              class="protocol-input"
              :placeholder="$t('common.plzSelect')"
              @change="handleWordLengthChange"
            >
              <ASelectOption v-for="item in wordLength" :key="item.dictEngValue" :value="item.dictValue">
                {{ item.dictValue }}
              </ASelectOption>
            </ASelect>
          </AFormItem>
        </ACol>
        <ACol v-if="isS7Protocol" :span="8">
          <AFormItem :label="$t('setupProtocol.protocolParamFields.quantity')" name="quantity">
            <AInputNumber
              v-model:value="customParamsForm.quantity"
              class="protocol-input"
              :placeholder="$t('common.plzEnter')"
              :min="0"
              :precision="0"
            />
          </AFormItem>
        </ACol>
        <ACol :span="8">
          <AFormItem :label="$t('setupProtocol.protocolParamFields.coefficient')" name="coefficient">
            <AInputNumber
              v-model:value="customParamsForm.coefficient"
              class="protocol-input"
              :placeholder="$t('common.plzEnter')"
              :min="0"
            />
          </AFormItem>
        </ACol>
        <ACol :span="8">
          <AFormItem :label="$t('setupProtocol.protocolParamFields.isHighFrequencyParameter')" name="isHighFreqParam">
            <ASelect
              v-model:value="customParamsForm.isHighFreqParam"
              class="protocol-input"
              :placeholder="$t('common.plzSelect')"
              @change="handleIsHighFreqParamChange"
            >
              <ASelectOption v-for="item in isHighFreqParam" :key="item.dictEngValue" :value="item.dictValue">
                {{ item.dictValue }}
              </ASelectOption>
            </ASelect>
          </AFormItem>
        </ACol>
        <ACol :span="8">
          <AFormItem :label="$t('setupProtocol.protocolParamFields.readCalculationFormula')" name="readCalcFormula">
            <AInput
              v-model:value="customParamsForm.readCalcFormula"
              class="protocol-input"
              :placeholder="$t('common.plzEnter')"
            />
          </AFormItem>
        </ACol>
        <ACol :span="8">
          <AFormItem :label="$t('setupProtocol.protocolParamFields.writeCalculationFormula')" name="writeCalcFormula">
            <AInput
              v-model:value="customParamsForm.writeCalcFormula"
              class="protocol-input"
              :placeholder="$t('common.plzEnter')"
            />
          </AFormItem>
        </ACol>
        <ACol :span="8">
          <AFormItem :label="$t('setupProtocol.protocolParamFields.decimalPlaces')" name="decimalPlace">
            <AInputNumber
              v-model:value="customParamsForm.decimalPlace"
              class="protocol-input"
              :placeholder="$t('common.plzEnter')"
              :min="0"
              :precision="0"
            />
          </AFormItem>
        </ACol>
      </ARow>
    </AForm>
  </AModal>
</template>

<style lang="scss" scoped>
.protocol-input {
  width: 100%;
}
</style>
