<!--
  ~ Licensed to Apache Software Foundation (ASF) under one or more contributor
  ~ license agreements. See the NOTICE file distributed with
  ~ this work for additional information regarding copyright
  ~ ownership. Apache Software Foundation (ASF) licenses this file to you under
  ~ the Apache License, Version 2.0 (the "License"); you may
  ~ not use this file except in compliance with the License.
  ~ You may obtain a copy of the License at
  ~
  ~     http://www.apache.org/licenses/LICENSE-2.0
  ~
  ~ Unless required by applicable law or agreed to in writing,
  ~ software distributed under the License is distributed on an
  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  ~ KIND, either express or implied.  See the License for the
  ~ specific language governing permissions and limitations
  ~ under the License.
-->

<script lang="ts" setup>
  import { reactive, ref, watch, getCurrentInstance } from 'vue';
  import { useRoute, useRouter } from 'vue-router';
  import TagEditor from './tagEditor.vue';
  import FieldsEditor from './fieldsEditor.vue';
  import type { FormInstance } from 'element-plus';
  import { ElMessage } from 'element-plus';
  import { createResources, editResources, getResourceOfAllType } from '@/api/index';
  import FormHeader from '../common/FormHeader.vue';

  const $loadingCreate = getCurrentInstance().appContext.config.globalProperties.$loadingCreate;
  const $loadingClose = getCurrentInstance().appContext.config.globalProperties.$loadingClose;
  const $bus = getCurrentInstance().appContext.config.globalProperties.mittBus;

  const router = useRouter();
  const route = useRoute();
  const ruleFormRef = ref<FormInstance>();
  const tagEditorRef = ref();
  const fieldEditorRef = ref();
  const rules = {
    group: [
      {
        required: true,
        message: 'Please enter the group',
        trigger: 'blur',
      },
    ],
    name: [
      {
        required: true,
        message: 'Please select the name',
        trigger: 'blur',
      },
    ],
  };

  const data = reactive({
    type: route.params.type,
    operator: route.params.operator,
    form: {
      group: route.params.group,
      name: route.params.group,
      modRevision: route.params.modRevision,
      interval: 1,
      intervalUnit: 'm',
      indexMode: false,
    },
  });

  const options = [
    {
      label: 'seconds',
      value: 's',
    },
    {
      label: 'minutes',
      value: 'm',
    },
    {
      label: 'hours',
      value: 'h',
    },
    {
      label: 'days',
      value: 'd',
    },
  ];

  watch(
    () => route,
    () => {
      data.form.group = route.params.group;
      data.form.name = route.params.name;
      data.form.modRevision = route.params.modRevision;
      data.type = String(route.params.type);
      data.operator = route.params.operator;
      initData();
    },
    {
      immediate: true,
      deep: true,
    },
  );
  const submit = async (formEl: FormInstance | undefined) => {
    if (!formEl) return;
    await formEl.validate(async (valid) => {
      if (valid) {
        const arr = tagEditorRef.value.getTagFamilies();
        const tagFamilies = [];
        const entity = [];
        const shardingKey = [];
        arr.forEach((item) => {
          const index = tagFamilies.findIndex((tagItem) => {
            return tagItem.name === item.tagFamily;
          });
          if (item.entity === true) {
            entity.push(item.tag);
          }
          if (item.shardingKey === true) {
            shardingKey.push(item.tag);
          }
          if (index >= 0) {
            let obj = {
              name: item.tag,
              type: item.type,
            };
            return tagFamilies[index].tags.push(obj);
          }
          let obj = {
            name: item.tagFamily,
            tags: [
              {
                name: item.tag,
                type: item.type,
              },
            ],
          };
          tagFamilies.push(obj);
        });
        if (entity.length === 0) {
          ElMessage({
            message: 'At least one Entity is required',
            type: 'error',
            duration: 5000,
          });
          return;
        }
        const form = {
          metadata: {
            group: data.form.group,
            name: data.form.name,
            modRevision: data.form.modRevision,
          },
          tagFamilies: tagFamilies,
          entity: {
            tagNames: entity,
          },
          shardingKey: {
            tagNames: shardingKey,
          },
        };
        if (data.type === 'measure') {
          const fields = fieldEditorRef.value.getFields();
          form['fields'] = fields;
          form['interval'] = data.form.interval + data.form.intervalUnit;
        }
        $loadingCreate();
        let params = {};
        params[data.type.toString()] = form;
        if (data.operator === 'edit' && data.form.group && data.form.name) {
          const res = await editResources(data.type, data.form.group, data.form.name, params);
          $loadingClose();
          if (res.error) {
            ElMessage({
              message: `Edit failed: ${res.error.message}`,
              type: 'error',
            });
            return;
          }
          ElMessage({
            message: 'Edit successed',
            type: 'success',
          });
          $bus.emit('refreshAside');
          $bus.emit('deleteResource', data.form.name);
          openResourses();
          return;
        }
        const res = await createResources(data.type, params);
        $loadingClose();
        if (res.error) {
          ElMessage({
            message: `Create failed: ${res.error.message}`,
            type: 'error',
          });
          return;
        }
        ElMessage({
          message: 'Create successed',
          type: 'success',
        });
        $bus.emit('refreshAside');
        $bus.emit('deleteGroup', data.form.group);
        openResourses();
      }
    });
  };
  function openResourses() {
    const route = {
      name: data.type + '',
      params: {
        group: data.form.group,
        name: data.form.name,
        operator: 'read',
        type: data.type + '',
      },
    };
    router.push(route);
    const add = {
      label: data.form.name,
      type: 'Read',
      route,
    };
    $bus.emit('AddTabs', add);
  }
  async function initData() {
    if (data.operator !== 'edit' || !data.form.group || !data.form.name) {
      return;
    }
    $loadingCreate();
    const res = await getResourceOfAllType(data.type, data.form.group, data.form.name);
    $loadingClose();
    if (res.error) {
      ElMessage({
        message: `Get ${data.type} detail failed: ${res.error.message}`,
        type: 'error',
      });
      return;
    }
    data.form.indexMode = res[String(data.type)]?.indexMode || false;
    const tagFamilies = res[String(data.type)]?.tagFamilies || [];
    const entity = res[String(data.type)]?.entity?.tagNames || [];
    const shardingKey = res[String(data.type)]?.shardingKey?.tagNames || [];
    const arr = [];
    tagFamilies.forEach((item) => {
      item.tags.forEach((tag) => {
        const entityIndex = entity.findIndex((entityItem) => {
          return entityItem === tag.name;
        });
        const shardingKeyIndex = shardingKey.findIndex((shardingKeyItem) => {
          return shardingKeyItem === tag.name;
        });
        const obj = {
          tagFamily: item.name,
          tag: tag.name,
          type: tag.type,
          entity: entityIndex >= 0 ? true : false,
          shardingKey: shardingKeyIndex >= 0 ? true : false,
        };
        arr.push(obj);
      });
    });
    tagEditorRef.value.setTagFamilies(arr);
    if (data.type === 'measure') {
      const fields = res[data.type.toString()].fields;
      const intervalArr = res[data.type.toString()].interval.split('');
      let interval = 0;
      let intervalUnit = '';
      intervalArr.forEach((char) => {
        let code = char.charCodeAt();
        if (code >= 48 && code < 58) {
          interval = interval * 10 + (char - 0);
        } else {
          intervalUnit = intervalUnit + char;
        }
      });
      data.form.interval = interval;
      data.form.intervalUnit = intervalUnit;
      fieldEditorRef.value.setFields(fields);
    }
    data.form.modRevision = res[data.type.toString()].metadata.modRevision;
  }
</script>

<template>
  <div>
    <el-card shadow="always">
      <template #header>
        <el-row>
          <el-col :span="20">
            <FormHeader :fields="{ ...data, catalog: data.type }" />
          </el-col>
          <el-col :span="4">
            <div class="flex align-item-center justify-end" style="height: 30px">
              <el-button size="small" type="primary" @click="submit(ruleFormRef)" color="#6E38F7">Submit</el-button>
            </div>
          </el-col>
        </el-row>
      </template>
      <el-form ref="ruleFormRef" :model="data.form" label-position="left" :rules="rules" :inline="true">
        <el-form-item label="group" prop="group">
          <el-input clearable disabled v-model="data.form.group"></el-input>
        </el-form-item>
        <el-form-item label="name" prop="name">
          <el-input style="width: 300px" clearable v-model="data.form.name"></el-input>
        </el-form-item>
        <el-form-item v-if="data.type === 'measure'" label="interval" prop="interval">
          <el-input-number v-model="data.form.interval" :min="1" />
          <el-select v-model="data.form.intervalUnit" style="width: 100px; margin-left: 5px">
            <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
          </el-select>
        </el-form-item>
        <el-form-item label="Index Mode" prop="indexMode">
          <span>{{ data.form.indexMode ? `Yes` : `No` }}</span>
        </el-form-item>
      </el-form>
      <TagEditor ref="tagEditorRef"></TagEditor>
      <el-divider v-if="data.type === 'measure'" border-style="dashed" />
      <FieldsEditor ref="fieldEditorRef" v-if="data.type === 'measure'"></FieldsEditor>
    </el-card>
  </div>
</template>

<style lang="scss" scoped>
  :deep(.el-card) {
    margin: 15px;
  }
</style>
