<template>
  <el-form :model="form" ref="formRef" :rules="formRules" label-width="auto">
    <el-row :gutter="16">
      <el-col :span="16">
        <el-form-item prop="ip" :label="$t('database.JdbcInstance.5oxhtcbo8ac0')" class="uniform-width">
          <el-select v-model.trim="form.ip" :placeholder="$t('database.JdbcInstance.5oxhtcbo9fg0')"
                     allow-create filterable style="width:441px">
            <el-option v-for="item in props.hostList" :key="item.value" :label="item.label" :value="item.value"></el-option>
          </el-select>
        </el-form-item>
      </el-col>
      <el-col :span="8">
        <el-form-item prop="port" label="/" label-width="2">
          <el-input-number v-model="form.port" :placeholder="$t('database.JdbcInstance.5oxhtcbo9xc0')"
                           :min="0" :max="65535" controls-position="right"
                           style="width:178px"
          />
        </el-form-item>
      </el-col>
    </el-row>
    <el-form-item prop="username" :label="$t('database.JdbcInstance.5oxhtcboa240')" class="uniform-width">
      <el-input v-model.trim="form.username" :placeholder="$t('database.JdbcInstance.5oxhtcboa7c0')"
                :disabled="props.jdbcType === JDBCType.Milvus || props.jdbcType === JDBCType.Elasticsearch" />
    </el-form-item>
    <el-row :gutter="16">
      <el-col :span="16">
        <el-form-item prop="password" :label="$t('database.JdbcInstance.5oxhtcboac00')" class="uniform-width">
          <el-input v-model.trim="form.password" :placeholder="$t('database.JdbcInstance.5oxhtcboags0')" show-password
                    allow-clear :disabled="props.jdbcType === JDBCType.Milvus || props.jdbcType === JDBCType.Elasticsearch" />
        </el-form-item>
      </el-col>
      <el-col :span="3">
        <el-link type="primary" @click="handleCurTest">  {{ $t('database.AddJdbc.5oxhkhimx5c0')}}</el-link>
      </el-col>
      <el-col :span="5">
        <span class="status-container">
          <span class="status-dot"
                :class="{
                  'error-dot': form.status === jdbcStatusEnum.fail,
                  'success-dot': form.status === jdbcStatusEnum.success,
                  'info-dot': form.status === undefined || form.status === jdbcStatusEnum.unTest
                }" />
          {{
            form.status === undefined || form.status === jdbcStatusEnum.unTest
              ? $t('database.AddJdbc.else1')
              : form.status === jdbcStatusEnum.success
                ? $t('database.AddJdbc.5oxhkhiks5k0')
                : $t('database.AddJdbc.5oxhkhimwfg0')
          }}
        </span>
      </el-col>
    </el-row>
    <div v-if="props.jdbcType !== JDBCType.Milvus && props.jdbcType !== JDBCType.Elasticsearch">
      <el-form-item :label="$t('database.JdbcInstance.5oxhtcboap00')" class="uniform-width">
        <el-table class="full-w" :data="form.props" size="small" :pagination="false">
          <el-table-column :label="t('database.JdbcInstance.5oxhtcboap00')" prop="name">
            <template #default="{ $index }">
              <el-input size="small" v-model.trim="form.props[$index].name" />
            </template>
          </el-table-column>
          <el-table-column :label="t('database.JdbcInstance.5oxhtcboap00')" prop="value">
            <template #default="{ $index }">
              <el-input size="small" v-model.trim="form.props[$index].value" />
            </template>
          </el-table-column>
          <el-table-column :label="t('database.JdbcInstance.5oxhtcboap00')" width="130">
            <template #default="{ $index }">
              <div class="flex-row-start">
                <el-link class="mr-s" @click="handleUrlAdd($index)">{{ $t('database.JdbcInstance.5oxhtcboatc0') }}</el-link>
                <el-link v-if="$index > 0" @click="handleUrlDel($index)">{{ $t('database.JdbcInstance.5oxhtcboaxc0') }}</el-link>
              </div>
            </template>
          </el-table-column>
        </el-table>
      </el-form-item>
    </div>
    <el-form-item prop="url" :label="$t('database.JdbcInstance.5oxhtcbob1s0')" class="uniform-width" style="margin-bottom: 0">
      <div class="flex-row" style="width: 100%;">
        {{ jdbcUrl }}
      </div>
    </el-form-item>
  </el-form>
</template>

<script setup lang="ts">
import { KeyValue } from '@/types/global'
import { ElForm } from 'element-plus'
import { PropType, ref, computed, watch } from 'vue'
import { jdbcNodePing } from '@/api/ops'
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
enum jdbcStatusEnum {
  unTest = -1,
  success = 1,
  fail = 0
}

const props = defineProps({
  formData: {
    type: Object as PropType<KeyValue>,
    required: true
  },
  hostList: {
    type: Object as PropType<KeyValue>,
    required: true
  },
  jdbcType: {
    type: String,
    required: true
  }
})

const emits = defineEmits([`update:formData`])
const form = computed({
  get: () => props.formData,
  set: (val) => {
    emits(`update:formData`, val)
  }
})

import { IpRegex } from '@/types/global'
import {encryptPassword} from "@/utils/jsencrypt";
import {JDBCType} from "@/types/jdbc";

const formRules = computed(() => {
  return {
    ip: [
      { required: true, message: t('database.JdbcInstance.5oxhtcbobhs0'), trigger: 'change' },
      {
        validator: (rule: any, value: any, callback: any) => {
          if (IpRegex.ipv4Reg.test(value) || IpRegex.ipv6Reg.test(value)) {
            callback()
          } else {
            callback(new Error(t('database.JdbcInstance.5oxhtcboblw0')))
          }
        },
        trigger: 'change'
      }
    ],
    port: [
      { required: true, message: t('database.JdbcInstance.5oxhtcbo9xc0'), trigger: 'blur' }
    ],
    username: [
      { required: props.jdbcType !== JDBCType.Milvus && props.jdbcType !== JDBCType.Elasticsearch, message: t('database.JdbcInstance.5oxhtcboa7c0'), trigger: 'blur' },
      {
        validator: (rule: any, value: any, callback: any) => {
          if (props.jdbcType !== JDBCType.Milvus && props.jdbcType !== JDBCType.Elasticsearch && !value.trim() ) {
            callback(new Error(t('database.JdbcInstance.5oxhtcbobtc0')))
          } else {
            callback()
          }
        },
        trigger: 'blur'
      }
    ],
    password: [
      { required: props.jdbcType !== JDBCType.Milvus && props.jdbcType !== JDBCType.Elasticsearch, message: t('database.JdbcInstance.5oxhtcboc2c0'), trigger: 'blur' },
      {
        validator: (rule: any, value: any, callback: any) => {
          if (!value.trim() && props.jdbcType !== JDBCType.Milvus && props.jdbcType !== JDBCType.Elasticsearch) {
            callback(new Error(t('database.JdbcInstance.5oxhtcbobtc0')))
          } else {
            callback()
          }
        },
        trigger: 'blur'
      }
    ]
  }
})

const handleUrlAdd = (index: number) => {
  form.value.props?.splice(index + 1, 0, {
    name: '',
    value: ''
  })
}

const handleUrlDel = (index: number) => {
  form.value.props?.splice(index, 1)
}

const handelTest = async (): Promise<KeyValue> => {
  let result = {
    id: form.value.id,
    res: false
  }
  let encryptPwd = ''
  if (form.value.password && form.value.password !== '') {
    encryptPwd = await encryptPassword(form.value.password)
  }
  const param = {
    username: form.value.username,
    password: encryptPwd,
    url: jdbcUrl.value,
    dbType: props.jdbcType
  }
  try {
    const res: KeyValue = await jdbcNodePing(param)
    if (Number(res.code) === 200 && res.data) {
      // ok
      result.res = true
      form.value.status = jdbcStatusEnum.success
    } else {
      form.value.status = jdbcStatusEnum.fail
    }
  } catch (err) {
    form.value.status = jdbcStatusEnum.fail
  }
  return result
}

const jdbcUrl = computed(() => {
  const queryParams = form.value.props
    ?.filter(item => item.name?.trim() && item.value?.trim())
    .map(item => `${item.name}=${item.value}`)
    .join('&') || ''

  const config = JDBCType.getConfig(props.jdbcType)
  const host = form.value.ip || '{IP}'
  const port = form.value.port || '{port}'

  let baseUrl = ''

  if (config.urlPattern) {
    let defaultDb = 'postgres'
    if (props.jdbcType === JDBCType.MySQL) {
      defaultDb = 'mysql'
    }
    baseUrl = config.urlPattern
      .replace('{host}', host)
      .replace('{port}', port.toString())
      .replace('{defaultDb}', defaultDb)

    return queryParams ? `${baseUrl}?${queryParams}` : baseUrl
  } else {
    baseUrl = `http://${host}:${port}`
    return baseUrl
  }
})

watch(jdbcUrl, (val) => {
  form.value.url = val
})
watch(() => props.jdbcType, (val) => {
  form.value.port = JDBCType.getDefaultPort(val)
})

const handleCurTest = async () => {
  const validRes = await formValidate()
  if (validRes.id === form.value.id && validRes.res) {
    await handelTest()
  }
}

const formRef = ref<null | InstanceType<typeof ElForm>>(null)

const formValidate = async (): Promise<KeyValue> => {
  if (!formRef.value) return { id: form.value.id, res: false }

  try {
    await formRef.value.validate()
    return { id: form.value.id, res: true }
  } catch (error) {
    return { id: form.value.id, res: false }
  }
}

defineExpose({
  handelTest,
  formValidate
})

</script>

<style scoped>
.uniform-width {
  width: 100%;
}

:deep(.el-form-item__content) {
  width: 320px;
}

:deep(.el-input),
:deep(.el-input-number),
:deep(.el-select) {
  max-width: 441px;

}

:deep(.el-input-number .el-input) {
  max-width: 441px;
}

:deep(.el-input-number .el-input__inner) {
  text-align: left;
}

.status-container {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  height: 24px;
  line-height: 1;
}


.status-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  margin: 16px;
}

.info-dot {
  background-color: var(--o-color-info-secondary);
}

.error-dot {
  background-color: var(--o-color-danger);
}

.success-dot {
  background-color: var(--o-color-success);
}
</style>