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

import SvgIcon from '@/components/SvgIcon.vue';
import { useDictData } from '@/hooks/dict-data';
import { useRequest } from '@/hooks/request';
import { useViewVisible } from '@/hooks/view-visible';
import { t } from '@/i18n';
import { addProtocolParam, getProtocolStandardParamList, 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 { Key, RowSelectionType } from 'ant-design-vue/es/table/interface';
import type { FormRules, PageParams, ProtocolParamInfo, ProtocolStandardParam } from '@/types';

interface Props {
  deviceType?: string;
  protocolId?: number;
  paramId?: number;
  paramName?: string;
  paramInfo?: ProtocolParamInfo;
  isModbusRtuProtocol?: boolean;
  isModbusTcpProtocol?: boolean;
  isS7Protocol?: boolean;
}

const props = defineProps<Props>();

const emit = defineEmits<{
  addLocalParams: [params: ProtocolStandardParam[]];
  editLocalParam: [param: ProtocolStandardParam];
  refreshList: [];
}>();

const isAddParams = ref(true);
const paramList = ref<ProtocolStandardParam[]>([]);
const paramTotal = ref(0);
const paramNameOrCode = ref('');
const pageParams = ref<PageParams>({
  pageIndex: 1,
  pageSize: 10,
  pageSorts: [
    {
      column: 'id',
      asc: true,
    },
  ],
});

const { isLoading, handleRequest } = useRequest();

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

const getStandardParams = () => {
  handleRequest(async () => {
    const { records, total } = await getProtocolStandardParamList({
      ...pageParams.value,
      platformParamName: paramNameOrCode.value,
      platformParamCode: paramNameOrCode.value,
      templateType: props.deviceType,
    });

    paramList.value = records;
    paramTotal.value = total;
  });
};

const { visible, showView, hideView } = useViewVisible();

watch(visible, () => {
  if (visible.value) {
    getStandardParams();
  }
});

const handleParamNameOrCodeChange = debounce(() => {
  pageParams.value.pageIndex = 1;
  getStandardParams();
}, 300);

const handlePageChange = (page: number, pageSize: number) => {
  pageParams.value.pageIndex = page;
  pageParams.value.pageSize = pageSize;
  getStandardParams();
};

const selectedParamIds = ref<number[]>([]);
const selectedParams = ref<ProtocolStandardParam[]>([]);

const selectionType = computed<RowSelectionType>(() => {
  return 'radio';
  // return isAddParams.value ? 'checkbox' : 'radio';
});

const handleParamSelectChange = (selectedRowKeys: Key[], selectedRows: ProtocolStandardParam[]) => {
  selectedParamIds.value = selectedRowKeys as number[];
  selectedParams.value = selectedRows;
};

const removeSelectedParam = ({ id }: ProtocolStandardParam) => {
  selectedParamIds.value = selectedParamIds.value.filter((item) => item !== id);
  selectedParams.value = selectedParams.value.filter((item) => item.id !== id);
};

const setSelectedParams = (param: ProtocolStandardParam) => {
  selectedParams.value = [param];
};

const clearSelectedParams = () => {
  selectedParamIds.value = [];
  selectedParams.value = [];
};

const { isLoading: isConfirmLoading, handleRequest: handleAddParamRequest } = useRequest();

const handleOk = () => {
  if (!selectedParams.value.length) {
    message.error(t('setupProtocol.plzSelectAtLeastOneParam'));
    return;
  }

  if (!props.protocolId) {
    if (isAddParams.value) {
      emit('addLocalParams', selectedParams.value);
    } else {
      emit('editLocalParam', selectedParams.value[0]);
    }

    hideView();
    return;
  }

  setParamsForm(selectedParams.value[0]);
  showFormView();

  // handleAddParamRequest(async () => {
  //   if (isAddParams.value) {
  //     for (const item of selectedParams.value) {
  //       await addProtocolParam({
  //         baseInfoId: props.protocolId,
  //         ...item,
  //       });
  //     }

  //     message.success(t('setupProtocol.addStandardParamsSuccessful'));
  //   } else {
  //     await updateProtocolParam({
  //       ...selectedParams.value[0],
  //       id: props.paramId,
  //     });

  //     message.success(t('setupProtocol.updateStandardParamsSuccessful'));
  //   }

  //   hideView();
  //   emit('refreshList');
  // });
};

const handleClose = () => {
  paramList.value = [];
  paramTotal.value = 0;
  paramNameOrCode.value = '';
  pageParams.value.pageIndex = 1;
  pageParams.value.pageSize = 10;
  clearSelectedParams();
};

const { visible: formVisible, showView: showFormView, hideView: hideFormView } = useViewVisible();
const { dictData: registerTypes, getDictData: getRegisterTypes } = useDictData(DictCode.RegisterType);
const { dictData: writeFuncCode, getDictData: getWriteFuncCode } = useDictData(DictCode.WriteFuncCode);
const { dictData: readFuncCode, getDictData: getReadFuncCode } = useDictData(DictCode.ReadFuncCode);

const standardParamsForm = reactive<Partial<ProtocolParamInfo>>({
  platformParamName: '',
  platformParamCode: '',
  unit: '',
  writeFuncCode: undefined,
  readFuncCode: undefined,
  addrLength: undefined,
  addrNumber: '',
  registerAddr: '',
  registerType: undefined,
  registerTypeCode: undefined,
});

const rules = computed<FormRules<ProtocolParamInfo>>(() => {
  return {
    platformParamName: [
      {
        required: true,
        message: t('common.plzEnter', { name: t('setupProtocol.protocolParamFields.paramName') }),
        trigger: 'blur',
      },
    ],
    platformParamCode: [
      {
        required: true,
        message: t('common.plzEnter', { name: t('setupProtocol.protocolParamFields.paramCode') }),
        trigger: 'blur',
      },
    ],
    readFuncCode: [
      {
        required: true,
        message: t('common.plzSelect', { name: t('setupProtocol.protocolParamFields.readFunctionCode') }),
        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',
      },
    ],
  };
});

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

const modalTitle = computed(() => {
  return t('setupProtocol.paramAddress');
  // return isAddParams.value ? t('setupProtocol.addStandardParams') : t('setupProtocol.updateStandardParams');
});

watch(formVisible, () => {
  if (formVisible.value && !isAddParams.value) {
    Object.assign(standardParamsForm, {
      writeFuncCode: props.paramInfo?.writeFuncCode,
      readFuncCode: props.paramInfo?.readFuncCode,
      addrLength: props.paramInfo?.addrLength,
      addrNumber: props.paramInfo?.addrNumber,
      registerAddr: props.paramInfo?.registerAddr,
      registerType: props.paramInfo?.registerType,
      registerTypeCode: props.paramInfo?.registerTypeCode,
    });
  }
});

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

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

onMounted(() => {
  handleAddParamRequest(async () => {
    await getRegisterTypes();
    await getWriteFuncCode();
    await getReadFuncCode();
  });
});

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

const formRef = ref<FormInstance>();

const handleFormOk = () => {
  formRef.value
    ?.validate()
    .then(() => {
      handleAddParamRequest(async () => {
        const standardParam = selectedParams.value[0];
        const paramInfo = {
          ...standardParam,
          ...standardParamsForm,
          baseInfoId: props.protocolId,
          platformProtocolInfoId: standardParam.id,
          paramName: props.paramName || standardParam.platformParamName,
        };

        if (isAddParams.value) {
          await addProtocolParam(paramInfo);
          message.success(t('setupProtocol.addStandardParamsSuccessful'));
        } else {
          await updateProtocolParam({
            ...props.paramInfo,
            ...standardParamsForm,
            baseInfoId: props.protocolId,
            platformProtocolInfoId: standardParam.id,
            paramName: props.paramName || standardParam.platformParamName,
            gatewayParamName: props.paramInfo?.gatewayParamName || standardParam.gatewayParamName,
            gatewayParamCode: props.paramInfo?.gatewayParamCode || standardParam.gatewayParamCode,
            id: props.paramId,
          });

          hideView();
          message.success(t('setupProtocol.updateStandardParamsSuccessful'));
        }

        hideFormView();
      });
    })
    .catch((err) => {
      console.error(err);
    });
};

const handleFormClose = () => {
  emit('refreshList');
  formRef.value?.clearValidate();

  Object.assign(standardParamsForm, {
    platformParamName: '',
    platformParamCode: '',
    unit: '',
    writeFuncCode: undefined,
    readFuncCode: undefined,
    addrLength: undefined,
    addrNumber: '',
    registerAddr: '',
    registerType: undefined,
    registerTypeCode: undefined,
  });

  if (!visible.value) {
    clearSelectedParams();
  }
};

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

<template>
  <AModal
    v-model:open="visible"
    :title="$t('setupProtocol.selectPlatformStandardParams')"
    :width="920"
    centered
    :after-close="handleClose"
    :ok-text="$t('common.nextStep')"
    @ok="handleOk"
  >
    <div class="params-container">
      <div class="params-list">
        <div class="params-list-header">
          <span class="params-label">{{ $t('setupProtocol.platformStandardParamList') }}</span>
          <AInput
            v-model:value="paramNameOrCode"
            class="params-list-input"
            :placeholder="$t('setupProtocol.plzEnterParamOrCode')"
            allow-clear
            @change="handleParamNameOrCodeChange"
          >
            <template #prefix>
              <SvgIcon name="search-o" :size="12" color="#B2B2B2" />
            </template>
          </AInput>
        </div>
        <ATable
          class="hvac-table"
          :data-source="paramList"
          row-key="id"
          :row-selection="{
            type: selectionType,
            selectedRowKeys: selectedParamIds,
            preserveSelectedRowKeys: true,
            onChange: handleParamSelectChange,
          }"
          :scroll="{ y: 285 }"
          :loading="isLoading"
          :pagination="{
            current: pageParams.pageIndex,
            pageSize: pageParams.pageSize,
            total: paramTotal,
            hideOnSinglePage: false,
            showLessItems: true,
            onChange: handlePageChange,
          }"
        >
          <ATableColumn
            :title="$t('setupProtocol.protocolParamFields.platformParamCode')"
            data-index="platformParamCode"
            :width="150"
          />
          <ATableColumn
            :title="$t('setupProtocol.protocolParamFields.platformParamName')"
            data-index="platformParamName"
            :width="150"
          />
          <ATableColumn :title="$t('setupProtocol.protocolParamFields.unit')" data-index="unit" />
          <!-- <ATableColumn :title="$t('setupProtocol.protocolParamFields.module')" data-index="module" /> -->
          <ATableColumn :title="$t('setupProtocol.protocolParamFields.groupName')" data-index="groupType" />
        </ATable>
      </div>
      <div class="params-selected">
        <div class="params-selected-header">
          <span class="params-label">{{ $t('setupProtocol.selectedParams') }} ({{ selectedParamIds.length }})</span>
          <SvgIcon class="cursor-pointer" name="delete" :size="21" color="#F56C6C" @click="clearSelectedParams" />
        </div>
        <div class="params-selected-list">
          <div class="params-selected-item" v-for="item in selectedParams" :key="item.id">
            <div class="ellipsis-text params-selected-item-label" :title="item.platformParamName">
              {{ item.platformParamName }}
            </div>
            <SvgIcon class="params-selected-item-delete" name="close-circle-o" @click="removeSelectedParam(item)" />
          </div>
        </div>
      </div>
    </div>
  </AModal>
  <AModal
    v-model:open="formVisible"
    :title="modalTitle"
    :width="920"
    :z-index="1001"
    centered
    :after-close="handleFormClose"
    :confirm-loading="isConfirmLoading"
    @ok="handleFormOk"
  >
    <AForm ref="formRef" :model="standardParamsForm" :rules="rules" layout="vertical" :disabled="!isAddParams">
      <ARow :gutter="30">
        <ACol :span="8">
          <AFormItem :label="$t('setupProtocol.protocolParamFields.platformParamName')" name="platformParamName">
            <AInput
              v-model:value="standardParamsForm.platformParamName"
              class="protocol-input"
              :placeholder="$t('common.plzEnter')"
              disabled
            />
          </AFormItem>
        </ACol>
        <ACol :span="8">
          <AFormItem :label="$t('setupProtocol.protocolParamFields.platformParamCode')" name="platformParamCode">
            <AInput
              v-model:value="standardParamsForm.platformParamCode"
              class="protocol-input"
              :placeholder="$t('common.plzEnter')"
              disabled
            />
          </AFormItem>
        </ACol>
        <ACol :span="8">
          <AFormItem :label="$t('setupProtocol.protocolParamFields.unit')" name="unit">
            <AInput
              v-model:value="standardParamsForm.unit"
              class="protocol-input"
              :placeholder="$t('common.plzEnter')"
              disabled
            />
          </AFormItem>
        </ACol>
        <ACol v-if="isModbusProtocol" :span="8">
          <AFormItem :label="$t('setupProtocol.protocolParamFields.writeFunctionCode')" name="writeFuncCode">
            <ASelect
              v-model:value="standardParamsForm.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="standardParamsForm.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')">
            <AInputNumber
              v-model:value="standardParamsForm.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="standardParamsForm.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="standardParamsForm.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="standardParamsForm.registerAddr"
              class="protocol-input"
              :placeholder="$t('common.plzEnter')"
            />
          </AFormItem>
        </ACol>
      </ARow>
    </AForm>
  </AModal>
</template>

<style lang="scss" scoped>
.params-container {
  display: flex;
  height: 470px;
  margin: 24px 0;
  border: 1px solid #e4e7ed;
  border-radius: 8px;
}

.params-label {
  font-size: 14px;
  font-weight: 500;
  line-height: 22px;
  color: #333;
}

.params-list {
  flex: 1;
  padding: 16px 24px;
}

.params-list-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 16px;
}

.params-list-input {
  width: 256px;
}

.params-selected {
  display: flex;
  flex-direction: column;
  width: 299px;
  padding: 16px 0;
  border-left: 1px solid #e4e7ed;
}

.params-selected-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 24px;
  margin-bottom: 24px;
}

.params-selected-list {
  flex: 1;
  padding: 0 24px;
  overflow-y: auto;
}

.params-selected-item {
  display: flex;
  align-items: center;
  cursor: pointer;

  &:hover {
    background-color: var(--antd-color-bg-text-hover);
  }
}

.params-selected-item-label {
  flex: 1;
  height: 24px;
  font-size: 14px;
  font-weight: 400;
  line-height: 24px;
  color: #666;
  text-align: left;
}

.params-selected-item-delete {
  font-size: 16px;
  color: var(--antd-color-text-secondary);
}

.protocol-input {
  width: 100%;
}
</style>
