<template>
  <div class="fc-style">
    <a-layout class="fc-container">
      <a-layout-content class="fc-main">
        <a-layout>
          <a-layout-sider theme="light" :width="300" class="cg-container">
            <div class="components">
              <a-collapse
                v-model:activeKey="componentGroupKey"
                :bordered="false"
                expand-icon-position="right"
                ghost
              >
                <a-collapse-panel v-for="(item, index) in componentList" :key="index + 1">
                  <template #header><NodeHead :nodeName="item.title" /> </template>
                  <ComponentGroup :fields="item.fields" :list="item.list" :isDisabled="!dbValue" />
                </a-collapse-panel>
              </a-collapse>
            </div>
          </a-layout-sider>
          <a-layout class="center-container">
            <AntdHeader
              v-bind="$props"
              @preview="handlerPreview"
              @upload-json="uploadJsonVisible = true"
              @generate-json="handleGenerateJson"
              @generate-code="handleGenerateCode"
              @clearable="handleClearable"
            >
              <slot name="header">
                <a-row
                  class="text-left w-[240px] absolute left-0"
                  align="middle"
                  v-if="isShowSelectDb"
                >
                  <a-col :span="8" align="right">
                    <span style="color: red">*</span>
                    数据库：
                  </a-col>
                  <a-col :span="16">
                    <DbSelect
                      :placeholder="t('请选择数据库')"
                      @change="handleDbChange"
                      :disabled="isDbDisabled"
                      v-model:value="dbValue"
                    />
                  </a-col>
                </a-row>
              </slot>
            </AntdHeader>
            <a-layout-content id="layoutId" :class="{ 'widget-empty': widgetForm.list }">
              <AntdWidgetForm
                ref="widgetFormRef"
                v-model:widgetForm="widgetForm"
                v-model:widgetFormSelect="widgetFormSelect"
              />
            </a-layout-content>
          </a-layout>
          <a-layout-sider theme="light" class="widget-config-container" :width="320">
            <a-layout class="layout-height">
              <a-tabs v-model:activeKey="configTab" centered style="background: #fff; height: 100%">
                <a-tab-pane key="widget" :tab="t('组件属性')">
                  <a-collapse
                    v-model:activeKey="chooseTab"
                    ghost
                    expandIconPosition="right"
                    v-if="widgetFormSelect"
                    style="margin: 5px 0 10px 10px"
                  >
                    <a-collapse-panel key="property">
                      <template #header><NodeHead nodeName="属性设置" /> </template>
                      <PropertyOption v-model:select="widgetFormSelect" :widgetForm="widgetForm" />
                    </a-collapse-panel>
                  </a-collapse>
                  <div class="widget-none" v-else>
                    <SvgIcon name="tool" :size="44" />
                    <p>{{ t('请先拖入组件后再查看组件属性') }}</p>
                  </div>
                </a-tab-pane>
              </a-tabs>
            </a-layout>
          </a-layout-sider>
        </a-layout>
      </a-layout-content>

      <a-modal
        v-model:visible="uploadJsonVisible"
        :title="t('导入JSON')"
        :width="800"
        @ok="handleUploadJson"
        :okText="t('确认')"
        :cancelText="t('取消')"
      >
        <a-alert
          type="info"
          :message="t('JSON格式如下，直接复制生成的json覆盖此处代码点击确定即可')"
          style="margin-bottom: 10px"
        />
        <CodeEditor v-model:value="jsonEg" language="json" />
      </a-modal>

      <PreviewModal @register="registerDrawer" :isDesignPreview="true" />

      <a-modal
        v-model:visible="generateJsonVisible"
        :title="t('生成JSON')"
        :okText="t('复制')"
        :cancelText="t('取消')"
        :width="800"
        @ok="handleCopyClick(generateJsonTemplate)"
      >
        <CodeEditor :value="generateJsonTemplate" language="json" readonly />
      </a-modal>

      <a-modal
        v-model:visible="dataJsonVisible"
        :title="t('获取数据')"
        :okText="t('复制')"
        :cancelText="t('取消')"
        :width="800"
        @ok="handleCopyClick(dataJsonTemplate)"
      >
        <CodeEditor :value="dataJsonTemplate" language="json" readonly />
      </a-modal>

      <a-modal
        v-model:visible="dataCodeVisible"
        :title="t('生产代码')"
        :okText="t('复制')"
        :cancelText="t('取消')"
        :width="800"
        @ok="handleCopyClick(dataCodeTemplate)"
      >
        <a-tabs type="card" v-model:activeKey="codeLanguage" :tabBarStyle="{ margin: 0 }">
          <a-tab-pane tab="Vue Component" :key="codeType.Vue">
            <CodeEditor :value="dataCodeTemplate" language="html" readonly />
          </a-tab-pane>
          <a-tab-pane tab="HTML" :key="codeType.Html">
            <CodeEditor :value="dataCodeTemplate" language="html" readonly />
          </a-tab-pane>
        </a-tabs>
      </a-modal>
    </a-layout>
  </div>
</template>

<script lang="ts">
  import {
    defineComponent,
    reactive,
    PropType,
    toRefs,
    watchEffect,
    provide,
    watch,
    inject,
    ref,
    onMounted,
    Ref,
  } from 'vue';
  import { message } from 'ant-design-vue';
  import { cloneDeep, merge, debounce } from 'lodash-es';
  import { CodeEditor } from '/@/components/CodeEditor';
  import ComponentGroup from '/@/components/Designer/src/components/ComponentGroup.vue';
  import AntdHeader from '/@/components/Designer/src/components/AntdHeader.vue';
  import AntdWidgetForm from '/@/components/Designer/src/components/AntdWidgetForm.vue';
  import PropertyOption from '/@/components/Designer/src/components/componentProperty/PropertyOption.vue';
  import { DbSelect } from '/@/components/DbSelect';
  import * as antd from '/@/components/Designer/src/types';
  import { copy } from '/@/utils';
  import generateCode from '/@/components/Designer/src/util/generateCode';
  import {
    WidgetForm,
    CodeType,
    PlatformType,
    upperFieldDb,
    TableCell,
    TableTh,
    noHaveTableAndField,
  } from '/@/components/Designer/src/types';
  import PreviewModal from '../PreviewModal.vue';
  import { useDrawer } from '/@/components/Drawer';
  import { GeneratorConfig } from '/@/model/generator/generatorConfig';
  import { SvgIcon } from '/@/components/Icon';
  import { useMessage } from '/@/hooks/web/useMessage';
  import { useI18n } from '/@/hooks/web/useI18n';
  import { NodeHead } from '/@/components/ModalPanel/index';

  const { t } = useI18n();
  export default defineComponent({
    name: 'AntdDesignForm',
    components: {
      AntdHeader,
      ComponentGroup,
      CodeEditor,
      AntdWidgetForm,
      PreviewModal,
      PropertyOption,
      SvgIcon,
      DbSelect,
      NodeHead,
    },
    props: {
      preview: {
        type: Boolean,
        default: true,
      },

      generateJson: {
        type: Boolean,
        default: true,
      },
      uploadJson: {
        type: Boolean,
        default: true,
      },
      clearable: {
        type: Boolean,
        default: true,
      },
      basicFields: {
        type: Array as PropType<Array<string>>,
        default: () => ['input', 'textarea', 'checkbox', 'radio', 'title'],
      },
    },
    setup(props) {
      const state = reactive({
        antd,
        codeType: CodeType,
        widgetForm: undefined as any,
        widgetFormSelect: undefined as any,
        generateFormRef: null as any,
        configTab: 'widget',
        chooseTab: 'property',
        previewVisible: false,
        uploadJsonVisible: false,
        dataJsonVisible: false,
        dataCodeVisible: false,
        generateJsonVisible: false,
        generateCodeVisible: false,
        generateJsonTemplate: JSON.stringify(antd.widgetForm, null, 2),
        dataJsonTemplate: '',
        dataCodeTemplate: '',
        codeLanguage: CodeType.Vue,
        jsonEg: JSON.stringify(antd.widgetForm, null, 2),
        componentGroupKey: ['1'],
        componentList: [
          {
            title: t('问卷组件'),
            fields: props.basicFields,
            list: antd.questionnaireComponents,
          },
        ],
      });
      state.widgetForm = inject('widgetForm');
      const generatorConfig = inject<GeneratorConfig>('generatorConfig') as GeneratorConfig;
      const designType = inject<string>('designType');
      let isFieldUpper = inject<Ref<boolean>>('isFieldUpper', ref(false));
      let mainTableName = inject<Ref<string>>('mainTableName', ref(''));

      const { notification } = useMessage();

      const isDbDisabled = ref(false);
      const dbValue = ref();
      const isShowSelectDb = ref(false);
      const tableCell = ref<TableCell>();
      const tableTh = ref<TableTh>();
      provide('tableCell', tableCell);
      provide('tableTh', tableTh);

      watch(
        () => generatorConfig.databaseId,
        (val) => {
          if (val) {
            dbValue.value = val;
            if (state.widgetForm?.list?.length) {
              isDbDisabled.value = true;
            }
          }
        },
        {
          immediate: true,
        },
      );

      onMounted(() => {
        isShowSelectDb.value = designType === 'code';
      });

      //注入数据
      provide('state', state);

      const handleUploadJson = () => {
        try {
          setJson(JSON.parse(state.jsonEg));
          state.uploadJsonVisible = false;
          message.success(t('上传成功'));
        } catch (error) {
          message.error(t('上传失败'));
        }
      };

      const handleCopyClick = (text: string) => {
        copy(text);
        message.success(t('Copy成功'));
      };

      const handleGenerateJson = () => {
        (state.generateJsonTemplate = JSON.stringify(state.widgetForm, null, 2)) &&
          (state.generateJsonVisible = true);
      };

      const handleGenerateCode = () => {
        state.codeLanguage = CodeType.Vue;
        state.dataCodeVisible = true;
      };

      watchEffect(() => {
        if (state.dataCodeVisible) {
          state.dataCodeTemplate = generateCode(
            state.widgetForm,
            state.codeLanguage,
            PlatformType.Antd,
          )!;
        }
      });

      const handleClearable = () => {
        state.widgetForm.list = [];
        merge(state.widgetForm, JSON.parse(JSON.stringify(antd.widgetForm)));
        state.widgetFormSelect = undefined;
      };

      const handleReset = () => state.generateFormRef.reset();

      const getJson = () => state.widgetForm;

      const setJson = (json: WidgetForm) => {
        state.widgetForm.list = [];
        merge(state.widgetForm, json);
        if (json.list?.length) {
          state.widgetFormSelect = json.list[0];
        }
      };
      const setWidgetFormSelect = (json: WidgetForm) => {
        if (json.list?.length) {
          state.widgetFormSelect = json.list[0];
        }
      };
      const handlerPreview = async () => {
        if (designType === 'data' && hasNoBindTableOrField(state.widgetForm.list)) {
          notification.error({
            message: t('提示'),
            description: t('请先将组件绑定表和字段'),
          }); //提示消息
        } else {
          openDrawer(true, { formJson: getJson() });
        }
      };

      const hasNoBindTableOrField = (component) => {
        const hasSubComponent = [
          'tab',
          'grid',
          'card',
          'one-for-one',
          'form',
          'table-layout',
          'sun-form',
        ];
        return component?.some((info) => {
          if (hasSubComponent.includes(info.type!)) {
            if (info.type === 'form' || info.type === 'one-for-one' || info.type === 'sun-form') {
              return hasNoBindTableOrField(info.children);
            } else if (info.type === 'table-layout') {
              return info.layout?.some((childInfo) => {
                return childInfo.list?.some((child) => {
                  return hasNoBindTableOrField(child.children);
                });
              });
            } else {
              return info.layout?.some((childInfo) => {
                return hasNoBindTableOrField(childInfo.list);
              });
            }
          } else {
            if (info.type === 'time-range' || info.type === 'date-range') {
              return !info.bindTable || !info.bindStartTime || !info.bindEndTime;
            }
            if (info.type === 'input' && info.options.isSave) {
              return false;
            }
            return noHaveTableAndField.includes(info.type)
              ? false
              : !info.bindTable || !info.bindField;
          }
        });
      };

      const handleDbChange = (value, option) => {
        generatorConfig.databaseId = value;
        if (option) isFieldUpper.value = upperFieldDb.includes(option.dbType);
        mainTableName.value = isFieldUpper.value
          ? mainTableName.value.toUpperCase()
          : mainTableName.value;
      };

      const clear = () => handleClearable();

      //这里使用了防抖 包裹  因为监听 state.widgetForm 会执行2次
      watch(
        () => state.widgetForm,
        debounce((val) => {
          isDbDisabled.value = !!val?.list?.length;
          generatorConfig.formJson = cloneDeep(val);
        }, 50),
        { deep: true },
      );

      //注册抽屉 获取外部操作抽屉得方法
      const [registerDrawer, { openDrawer }] = useDrawer();

      return {
        ...toRefs(state),
        handleUploadJson,
        handleCopyClick,
        handleGenerateJson,
        handleGenerateCode,
        handleClearable,
        handleReset,
        getJson,
        setJson,
        setWidgetFormSelect,
        clear,
        handlerPreview,
        registerDrawer,
        t,
        handleDbChange,
        isDbDisabled,
        isShowSelectDb,
        dbValue,
        tableCell,
        tableTh,
      };
    },
  });
</script>
<style scoped lang="less">
  .fc-style {
    height: 100%;
  }

  .layout-height {
    height: 100%;
    background-color: #f0f2f5;
  }

  :deep(.ant-collapse-header) {
    padding-left: 5px !important;
    margin: 10px 0;
    height: 24px;
    align-items: center !important;
  }

  :deep(.ant-collapse-content-box) {
    padding-top: 0 !important;
  }

  :deep(.ant-tabs) {
    height: 100%;
  }

  :deep(.ant-tabs-content-holder) {
    overflow-y: auto;
  }

  :deep(.ant-tabs-content-top) {
    height: 100%;
  }

  :deep(.ant-radio-group) {
    display: flex;

    .ant-radio-button-wrapper {
      display: flex;
      justify-content: center;
      align-items: center;
      flex: 1;
      padding: 3px 0 !important;
    }
  }

  .widget-none {
    height: 100%;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;

    p {
      margin: 10px;
      color: #cecece;
    }
  }

  :deep(.ant-tabs-nav) {
    margin-bottom: 8px;
  }

  :deep(.ant-form-item) {
    margin-bottom: 10px;
  }

  :deep(.ant-radio-group-small .ant-radio-button-wrapper) {
    padding: 3px 10px;
    box-sizing: content-box;
  }

  .cg-container {
    overflow-y: scroll;
    padding-left: 10px;
    box-sizing: border-box;

    :deep(.ant-tabs-content-holder) {
      padding: 0 10px 10px 0;
    }

    :deep(.ant-collapse-content-box) {
      padding: 0 !important;
    }

    :deep(.ant-collapse-header) {
      padding-left: 5px !important;
      height: 24px;
      align-items: center !important;
      margin: 10px 0;

      .ant-collapse-arrow {
        right: 2px;
      }
    }
  }

  .fc-container {
    height: 100%;
  }

  .ant-layout.ant-layout-has-sider {
    height: 100%;
  }

  .center-container {
    height: 100%;
    background-color: #fff;
    padding-bottom: 20px;
    box-sizing: border-box;
    border-left: 8px solid #f0f2f5;
    border-right: 8px solid #f0f2f5;

    .center-header {
      padding: 10px;
    }
  }
</style>
