<script>
import _ from 'lodash'
import VueJsonEditor from 'vue-json-editor-fix-cn'
import Plugin from '../mixins/plugin'

export default {
  name: 'Server',
  components: {
    VueJsonEditor,
  },
  mixins: [Plugin],
  data () {
    return {
      key: 'server',
      dnsMappings: [],
      speedTestList: [],
      whiteList: [],
    }
  },
  computed: {
    speedDnsOptions () {
      const options = []
      if (!this.config || !this.config.server || !this.config.server.dns || !this.config.server.dns.providers) {
        return options
      }
      _.forEach(this.config.server.dns.providers, (dnsConfig, key) => {
        options.push({
          value: key,
          label: key,
        })
      })
      return options
    },
  },
  created () {
  },
  mounted () {
    this.registerSpeedTestEvent()
  },
  methods: {
    async onCrtSelect () {
      const value = await this.$api.fileSelector.open()
      if (value != null && value.length > 0) {
        this.config.server.setting.rootCaFile.certPath = value[0]
      }
    },
    async onKeySelect () {
      const value = await this.$api.fileSelector.open()
      if (value != null && value.length > 0) {
        this.config.server.setting.rootCaFile.keyPath = value[0]
      }
    },
    ready () {
      this.initDnsMapping()
      this.initWhiteList()
      if (this.config.server.dns.speedTest.dnsProviders) {
        this.speedDns = this.config.server.dns.speedTest.dnsProviders
      }
    },
    async applyBefore () {
      this.submitDnsMapping()
      this.submitWhiteList()
    },
    async applyAfter () {
      if (this.status.server.enabled) {
        return this.$api.server.restart()
      }
    },
    // dnsMapping
    initDnsMapping () {
      this.dnsMappings = []
      for (const key in this.config.server.dns.mapping) {
        const value = this.config.server.dns.mapping[key]
        this.dnsMappings.push({
          key,
          value,
        })
      }
    },
    submitDnsMapping () {
      const dnsMapping = {}
      for (const item of this.dnsMappings) {
        if (item.key) {
          dnsMapping[item.key] = item.value
        }
      }
      this.config.server.dns.mapping = dnsMapping
    },
    deleteDnsMapping (item, index) {
      this.dnsMappings.splice(index, 1)
    },
    restoreDefDnsMapping (item, index) {

    },
    addDnsMapping () {
      this.dnsMappings.unshift({ key: '', value: 'quad9' })
    },

    // whiteList
    initWhiteList () {
      this.whiteList = []
      for (const key in this.config.server.whiteList) {
        const value = this.config.server.whiteList[key]
        this.whiteList.push({
          key,
          value,
        })
      }
    },
    submitWhiteList () {
      const whiteList = {}
      for (const item of this.whiteList) {
        if (item.key) {
          whiteList[item.key] = item.value
        }
      }
      this.config.server.whiteList = whiteList
    },
    deleteWhiteList (item, index) {
      this.whiteList.splice(index, 1)
    },
    addWhiteList () {
      this.whiteList.unshift({ key: '', value: true })
    },
    getSpeedTestConfig () {
      return this.config.server.dns.speedTest
    },
    addSpeedHostname () {
      this.getSpeedTestConfig().hostnameList.unshift('')
    },
    delSpeedHostname (item, index) {
      this.getSpeedTestConfig().hostnameList.splice(index, 1)
    },
    reSpeedTest () {
      this.$api.server.reSpeedTest()
    },
    registerSpeedTestEvent () {
      const listener = async (event, message) => {
        console.log('get speed event', event, message)
        if (message.key === 'getList') {
          this.speedTestList = message.value
        }
      }
      this.$api.ipc.on('speed', listener)
      const interval = this.startSpeedRefreshInterval()
      this.reloadAllSpeedTester()

      this.$once('hook:beforeDestroy', () => {
        clearInterval(interval)
        this.$api.ipc.removeAllListeners('speed')
      })
    },
    async reloadAllSpeedTester () {
      this.$api.server.getSpeedTestList()
    },
    startSpeedRefreshInterval () {
      return setInterval(() => {
        this.reloadAllSpeedTester()
      }, 5000)
    },
    async handleTabChange (key) {
      if (key !== '2' && key !== '3' && key !== '5' && key !== '6' && key !== '7') {
        return
      }

      // 规避 vue-json-editor 内容只填充输入框一半的问题
      setTimeout(() => {
        window.dispatchEvent(new Event('resize'))
      }, 10)
    },
  },
}
</script>

<template>
  <ds-container>
    <template slot="header">
      加速服务设置
    </template>

    <div style="height: 100%" class="json-wrapper">
      <a-tabs
        v-if="config"
        default-active-key="1"
        tab-position="left"
        :style="{ height: '100%' }"
        @change="handleTabChange"
      >
        <a-tab-pane key="1" tab="基本设置">
          <div style="padding-right:10px">
            <a-form-item label="代理服务:" :label-col="labelCol" :wrapper-col="wrapperCol">
              <a-checkbox v-model="config.server.enabled">
                随应用启动
              </a-checkbox>
              <a-tag v-if="status.proxy.enabled" color="green">
                当前已启动
              </a-tag>
              <a-tag v-else color="red">
                当前未启动
              </a-tag>
            </a-form-item>
            <a-form-item label="绑定IP" :label-col="labelCol" :wrapper-col="wrapperCol">
              <a-input v-model="config.server.host" />
              <div class="form-help">
                你可以设置为<code>0.0.0.0</code>，让其他电脑可以使用此代理服务
              </div>
            </a-form-item>
            <a-form-item label="代理端口" :label-col="labelCol" :wrapper-col="wrapperCol">
              <a-input-number v-model="config.server.port" :min="0" :max="65535" :precision="0" />
              <div class="form-help">
                修改后需要重启应用
              </div>
            </a-form-item>
            <hr>
            <a-form-item label="全局校验SSL" :label-col="labelCol" :wrapper-col="wrapperCol">
              <a-checkbox v-model="config.server.setting.NODE_TLS_REJECT_UNAUTHORIZED">
                NODE_TLS_REJECT_UNAUTHORIZED
              </a-checkbox>
              <div class="form-help">
                高风险操作，没有特殊情况请勿关闭
              </div>
            </a-form-item>
            <a-form-item label="代理校验SSL" :label-col="labelCol" :wrapper-col="wrapperCol">
              <a-checkbox v-model="config.server.setting.verifySsl">
                校验加速目标网站的ssl证书
              </a-checkbox>
              <div class="form-help">
                如果目标网站证书有问题，但你想强行访问，可以临时关闭此项
              </div>
            </a-form-item>
            <a-form-item label="根证书" :label-col="labelCol" :wrapper-col="wrapperCol">
              <a-input-search
                v-model="config.server.setting.rootCaFile.certPath" addon-before="Cert" enter-button="选择"
                :title="config.server.setting.rootCaFile.certPath"
                @search="onCrtSelect"
              />
              <a-input-search
                v-model="config.server.setting.rootCaFile.keyPath" addon-before="Key" enter-button="选择"
                :title="config.server.setting.rootCaFile.keyPath"
                @search="onKeySelect"
              />
            </a-form-item>
            <hr>
            <a-form-item label="启用拦截" :label-col="labelCol" :wrapper-col="wrapperCol">
              <a-checkbox v-model="config.server.intercept.enabled">
                启用拦截
              </a-checkbox>
              <div class="form-help">
                关闭拦截，且关闭增强功能时，就不需要安装根证书，退化为安全模式
              </div>
            </a-form-item>
            <a-form-item label="启用脚本" :label-col="labelCol" :wrapper-col="wrapperCol">
              <a-checkbox v-model="config.server.setting.script.enabled">
                允许插入并运行脚本
              </a-checkbox>
              <div class="form-help">
                关闭后，<code>Github油猴脚本</code>也将关闭
              </div>
            </a-form-item>
          </div>
        </a-tab-pane>
        <a-tab-pane key="2" tab="拦截设置">
          <VueJsonEditor
            ref="editor" v-model="config.server.intercepts" style="height:100%" mode="code"
            :show-btns="false" :expanded-on-start="true"
          />
        </a-tab-pane>
        <a-tab-pane key="3" tab="超时时间设置">
          <div style="height:100%;display:flex;flex-direction:column">
            <a-form-item label="默认超时时间" :label-col="labelCol" :wrapper-col="wrapperCol">
              请求：<a-input-number v-model="config.server.setting.defaultTimeout" :step="1000" :min="1000" :precision="0" /> ms，对应<code>timeout</code>配置<br>
              连接：<a-input-number v-model="config.server.setting.defaultKeepAliveTimeout" :step="1000" :min="1000" :precision="0" /> ms，对应<code>keepAliveTimeout</code>配置
            </a-form-item>
            <hr style="margin-bottom:15px">
            <div>这里指定域名的超时时间：<span class="form-help">（域名配置可使用通配符或正则）</span></div>
            <VueJsonEditor
              ref="editor" v-model="config.server.setting.timeoutMapping" style="flex-grow:1;min-height:300px;margin-top:10px" mode="code"
              :show-btns="false" :expanded-on-start="true"
            />
          </div>
        </a-tab-pane>
        <a-tab-pane key="4" tab="域名白名单">
          <a-row style="margin-top:10px">
            <a-col span="21">
              <div>这里配置的域名不会通过代理</div>
            </a-col>
            <a-col span="3">
              <a-button style="margin-left:8px" type="primary" icon="plus" @click="addWhiteList()" />
            </a-col>
          </a-row>
          <a-row v-for="(item, index) of whiteList" :key="index" :gutter="10" style="margin-top: 5px">
            <a-col :span="21">
              <a-input v-model="item.key" :disabled="item.value === false" />
            </a-col>
            <a-col :span="3">
              <a-button v-if="item.value !== false" type="danger" icon="minus" @click="deleteWhiteList(item, index)" />
            </a-col>
          </a-row>
        </a-tab-pane>
        <a-tab-pane key="5" tab="自动兼容程序">
          <div style="height:100%;display:flex;flex-direction:column">
            <div>
              说明：<code>自动兼容程序</code>会自动根据错误信息进行兼容性调整，并将兼容设置保存在 <code>~/.dev-sidecar/automaticCompatibleConfig.json</code> 文件中。但并不是所有的兼容设置都是正确的，所以需要通过以下配置来覆盖错误的兼容设置。
            </div>
            <VueJsonEditor
              ref="editor" v-model="config.server.compatible" style="flex-grow:1;min-height:300px;margin-top:10px;" mode="code"
              :show-btns="false" :expanded-on-start="true"
            />
          </div>
        </a-tab-pane>
        <a-tab-pane key="6" tab="IP预设置">
          <div style="height:100%;display:flex;flex-direction:column">
            <div>
              提示：<code>IP预设置</code>功能，优先级高于 <code>DNS设置</code>
              <span class="form-help">（域名配置可使用通配符或正则）</span>
            </div>
            <VueJsonEditor
              ref="editor" v-model="config.server.preSetIpList" style="flex-grow:1;min-height:300px;margin-top:10px;" mode="code"
              :show-btns="false" :expanded-on-start="true"
            />
          </div>
        </a-tab-pane>
        <a-tab-pane key="7" tab="DNS服务管理">
          <VueJsonEditor
            ref="editor" v-model="config.server.dns.providers" style="height:100%" mode="code"
            :show-btns="false" :expanded-on-start="true"
          />
        </a-tab-pane>
        <a-tab-pane key="8" tab="DNS设置">
          <div>
            <a-row style="margin-top:10px">
              <a-col span="21">
                <div>这里配置哪些域名需要通过国外DNS服务器获取IP进行访问</div>
              </a-col>
              <a-col span="3">
                <a-button style="margin-left:8px" type="primary" icon="plus" @click="addDnsMapping()" />
              </a-col>
            </a-row>
            <a-row v-for="(item, index) of dnsMappings" :key="index" :gutter="10" style="margin-top: 5px">
              <a-col :span="15">
                <a-input v-model="item.key" :disabled="item.value === false" />
              </a-col>
              <a-col :span="6">
                <a-select v-model="item.value" :disabled="item.value === false" style="width: 100%">
                  <a-select-option v-for="(item) of speedDnsOptions" :key="item.value" :value="item.value">
                    {{ item.value }}
                  </a-select-option>
                </a-select>
              </a-col>
              <a-col :span="3">
                <a-button v-if="item.value !== false" type="danger" icon="minus" @click="deleteDnsMapping(item, index)" />
                <a-button v-if="item.value === false" type="primary" icon="checked" @click="restoreDefDnsMapping(item, index)" />
              </a-col>
            </a-row>
          </div>
        </a-tab-pane>
        <a-tab-pane key="9" tab="IP测速">
          <div class="ip-tester" style="padding-right: 10px">
            <a-alert type="info" message="对从DNS获取到的IP进行测速，使用速度最快的IP进行访问（注意：对使用了增强功能的域名没啥用）" />
            <a-form-item label="开启DNS测速" :label-col="labelCol" :wrapper-col="wrapperCol">
              <a-checkbox v-model="getSpeedTestConfig().enabled">
                启用
              </a-checkbox>
            </a-form-item>
            <a-form-item label="自动测试间隔" :label-col="labelCol" :wrapper-col="wrapperCol">
              <a-input-number v-model="getSpeedTestConfig().interval" :step="1000" :min="1" :precision="0" /> ms
            </a-form-item>
            <!-- <a-form-item label="慢速IP阈值" :label-col="labelCol" :wrapper-col="wrapperCol">
              <a-input-number v-model="config.server.setting.lowSpeedDelay" :step="10" :min="100" :precision="0" /> ms
            </a-form-item> -->
            <div>使用以下DNS获取IP进行测速</div>
            <a-row style="margin-top:10px">
              <a-col span="24">
                <a-checkbox-group
                  v-model="getSpeedTestConfig().dnsProviders"
                  :options="speedDnsOptions"
                />
              </a-col>
            </a-row>
            <a-row :gutter="10" class="mt20">
              <a-col :span="21">
                以下域名在启动后立即进行测速，其他域名在第一次访问时才测速
              </a-col>
              <a-col :span="2">
                <a-button style="margin-left:10px" type="primary" icon="plus" @click="addSpeedHostname()" />
              </a-col>
            </a-row>
            <a-row
              v-for="(item, index) of getSpeedTestConfig().hostnameList" :key="index" :gutter="10"
              style="margin-top: 5px"
            >
              <a-col :span="21">
                <a-input v-model="getSpeedTestConfig().hostnameList[index]" />
              </a-col>
              <a-col :span="2">
                <a-button style="margin-left:10px" type="danger" icon="minus" @click="delSpeedHostname(item, index)" />
              </a-col>
            </a-row>

            <a-divider />
            <a-row :gutter="10" class="mt10">
              <a-col span="24">
                <a-button type="primary" icon="plus" @click="reSpeedTest()">
                  立即重新测速
                </a-button>
                <a-button class="md-ml-10" type="primary" icon="reload" @click="reloadAllSpeedTester()">
                  刷新
                </a-button>
              </a-col>
            </a-row>

            <a-row :gutter="20">
              <a-col v-for="(item, key) of speedTestList" :key="key" span="12">
                <a-card size="small" class="md-mt-10" :title="key">
                  <a slot="extra" href="javascript:void(0)" :title="key" style="cursor:default">
                    <a-icon v-if="item.alive.length > 0" type="check" />
                    <a-icon v-else type="info-circle" />
                  </a>
                  <a-tag
                    v-for="(element, index) of item.backupList" :key="index" style="margin:2px;"
                    :title="element.dns" :color="element.time ? (element.time > config.server.setting.lowSpeedDelay ? 'orange' : 'green') : 'red'"
                  >
                    {{ element.host }} {{ element.time }}{{ element.time ? 'ms' : '' }} {{ element.dns }}
                  </a-tag>
                </a-card>
              </a-col>
            </a-row>
          </div>
        </a-tab-pane>
      </a-tabs>
    </div>
    <template slot="footer">
      <div class="footer-bar">
        <a-button :loading="resetDefaultLoading" class="md-mr-10" icon="sync" @click="resetDefault()">
          恢复默认
        </a-button>
        <a-button :loading="applyLoading" icon="check" type="primary" @click="apply()">
          应用
        </a-button>
      </div>
    </template>
  </ds-container>
</template>

<style lang="scss">
.json-wrapper {
  .ant-drawer-wrapper-body {
    display: flex;
    flex-direction: column;

    .ant-drawer-body {
      flex: 1;
      height: 0;
    }
  }

  .jsoneditor-vue {
    height: 100%;
  }

  .ant-tabs {
    height: 100%;
  }

  .ant-tabs-content {
    height: 100%;
  }

  .ant-tabs-tabpane-active {
    height: 100%;
    overflow-y: auto;
    overflow-x: hidden;
  }
}
</style>
