<template>
  <wrapper
    class="c-profile"
    fill
    margin
    background
  >
    <div class="l-flex__none l-flex--col center c-profile__header has-padding">
      <div
        class="o-avatar u-pointer"
        @click="onAvatarClick"
      >
        <i
          class="o-avatar__img"
          :style="avatarStyle"
        />
        <i class="o-avatar__upload el-icon-camera" />
        <input
          ref="upload"
          type="file"
          accept="image/*"
          style="display: none;"
          @change="onUpload"
        >
      </div>
      <div class="u-bold">{{ name }}</div>
    </div>
    <div class="l-flex__fill u-overflow-y--auto">
      <warning
        v-if="error"
        @retry="getUserInfo"
      />
      <div
        v-else
        class="c-form has-padding"
      >
        <div class="c-form__section">
          <span class="c-form__label">手机：</span>
          <el-input
            v-model="phone"
            class="c-form__item"
            @change="onPhoneChange"
            @keydown.enter="$event.target.blur()"
          />
        </div>
        <div class="c-form__section has-bottom-padding">
          <span class="c-form__label">邮箱：</span>
          <el-input
            v-model="email"
            class="c-form__item"
            @change="onEmailChange"
            @keydown.enter="$event.target.blur()"
          />
        </div>
        <div class="c-form__section">
          <i class="o-wechat" />
          <div
            class="has-padding u-pointer"
            :class="color"
            @click="onClickWechat"
          >
            {{ tip }}
          </div>
        </div>
      </div>
    </div>
    <el-dialog
      :visible.sync="showQr"
      custom-class="c-preview"
      width="0"
      @close="onCloseQr"
    >
      <div class="c-wechat has-padding">
        <div class="l-flex--row center has-bottom-padding">
          <i class="c-sibling-item o-wechat" />
          <span class="c-sibling-item u-color--black u-bold">请使用微信扫一扫</span>
        </div>
        <div
          v-loading="loading"
          class="c-wechat__wrapper"
          :class="{ retry }"
          @click="getQr"
        >
          <img
            class="c-wechat__qr"
            :src="qr"
          >
        </div>
      </div>
    </el-dialog>
  </wrapper>
</template>

<script>
import { mapState } from 'vuex'
import {
  userinfo,
  updateUser,
  getTicket
} from '@/api/user'
import {
  validPhone,
  validEmail
} from '@/utils/validate'

export default {
  name: 'Profile',
  data () {
    return {
      error: false,
      user: null,
      avatar: '',
      phone: '',
      email: '',
      wechat: '',
      showQr: false,
      qr: null,
      loading: false,
      retry: false
    }
  },
  computed: {
    ...mapState('user', ['name']),
    avatarStyle () {
      const avatar = this.avatar
      return avatar ? {
        backgroundImage: `url("${avatar}")`
      } : null
    },
    tip () {
      return this.wechat ? '解除绑定' : '绑定微信'
    },
    color () {
      return this.wechat ? 'u-color--error' : 'u-color--primary'
    }
  },
  created () {
    this.$timer = null
    this.$checkTimer = null
    this.getUserInfo()
  },
  beforeDestroy () {
    this.onCloseQr()
    clearInterval(this.$checkTimer)
  },
  methods: {
    onAvatarClick () {
      this.$refs.upload.click()
    },
    onUpload (e) {
      const file = e.target.files[0]
      e.target.value = null
      if (file.size >= 1024 * 1024) {
        this.$message({
          type: 'warning',
          message: '请选择1M以下的图片'
        })
        return
      }
      const reader = new FileReader()
      reader.onload = () => {
        this.avatar = reader.result
      }
      reader.readAsDataURL(file)
    },
    getUserInfo () {
      this.error = false
      userinfo().then(
        this.setUserInfo,
        () => {
          this.error = true
        }
      )
    },
    setUserInfo (data) {
      this.avatar = this.getOrCreateAttribute(data, 'avatar', '')
      this.phone = this.getOrCreateAttribute(data, 'phone', '')
      this.email = data.email ?? ''
      this.wechat = this.getOrCreateAttribute(data, 'wechat', '')
      this.user = data
    },
    getOrCreateAttribute (user, key, defaults = '') {
      if (!user.attributes[key]) {
        user.attributes[key] = [defaults]
      }
      return user.attributes[key][0]
    },
    updateUser (data, meesage) {
      return updateUser(this.user.id, data, meesage)
    },
    changeAttribute (key, value, meesage) {
      if (this.user.attributes[key][0] !== value) {
        this.updateUser({
          attributes: {
            ...this.user.attributes,
            [key]: [value]
          }
        }, meesage).then(
          () => {
            this.user.attributes[key][0] = value
          },
          () => {
            this.resetAttribute(key)
          }
        )
      }
    },
    resetAttribute (key) {
      this[key] = this.user.attributes[key][0]
    },
    resetProp (key) {
      this[key] = this.user[key] ?? ''
    },
    onPhoneChange () {
      if (!this.phone) {
        this.$message({
          type: 'warning',
          message: '手机号不能为空'
        })
        this.resetAttribute('phone')
        return
      }
      if (!validPhone(this.phone)) {
        this.$message({
          type: 'warning',
          message: '手机号格式错误'
        })
        this.resetAttribute('phone')
        return
      }
      this.changeAttribute('phone', this.phone, '更新手机号')
    },
    onEmailChange () {
      if (!this.email) {
        this.$message({
          type: 'warning',
          message: '邮箱不能为空'
        })
        this.resetProp('email')
        return
      }
      if (!validEmail(this.email)) {
        this.$message({
          type: 'warning',
          message: '邮箱格式错误'
        })
        this.resetProp('email')
        return
      }
      this.updateUser({ email: this.email }, '更新邮箱').then(
        () => {
          this.user.email = this.email
        },
        () => {
          this.resetProp('email')
        }
      )
    },
    onClickWechat () {
      if (this.wechat) {
        this.$confirm(
          '解除绑定后将无法再收到消息推送',
          '确定解绑微信？',
          { type: 'warning' }
        ).then(
          () => {
            this.changeAttribute('wechat', this.wechat = '', '解绑微信')
          }
        )
      } else {
        this.showQr = true
        this.getQr()
      }
    },
    onCloseQr () {
      this.showQr = false
      clearTimeout(this.$timer)
    },
    getQr () {
      if (this.loading || this.qr && !this.retry) {
        return
      }
      this.fetchQr()
    },
    resetQr () {
      clearInterval(this.$checkTimer)
      this.$checkTimer = null
      this.qr = ''
      this.retry = false
    },
    fetchQr () {
      if (!this.showQr) {
        this.qr = ''
        return
      }
      if (!this.qr || this.retry) {
        this.loading = true
      }
      this.retry = false
      clearTimeout(this.$timer)
      getTicket(this.user.id).then(
        ({ data }) => {
          if (!this.wechat) {
            try {
              const { expire_seconds, ticket } = JSON.parse(data)
              this.qr = `https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=${ticket}`
              // 提前10秒重新获取
              this.$timer = setTimeout(this.fetchQr, (expire_seconds > 10 ? expire_seconds - 10 : expire_seconds) * 1000)
              this.checkBind()
            } catch (e) {
              console.warn(e)
              this.retry = true
            }
          }
        },
        () => {
          if (!this.wechat) {
            this.retry = true
          }
        }
      ).finally(() => {
        this.loading = false
      })
    },
    checkBind () {
      if (!this.wechat && !this.$checkTimer) {
        this.$checkTimer = setInterval(this.check, 2000)
      }
    },
    check () {
      userinfo(true).then(data => {
        const wechat = data.attributes.wechat?.[0]
        if (wechat) {
          this.$message({
            type: 'success',
            message: '绑定微信成功'
          })
          this.setUserInfo(data)
          this.onCloseQr()
          this.resetQr()
        }
      })
    }
  }
}
</script>

<style lang="scss" scoped>
.c-profile {
  overflow: hidden;

  &__header {
    justify-content: space-between;
    height: 140px;
    color: #fff;
    line-height: 1;
    background-color: $blue;
  }
}

.o-avatar {
  display: inline-block;
  position: relative;
  width: 80px;
  height: 80px;
  padding: 2px;
  border-radius: 50%;
  background-color: #fff;

  &__img {
    display: inline-block;
    width: 100%;
    height: 100%;
    border-radius: 50%;
    background: url("~@/assets/icon_avatar.png") 0 0 / 100% 100% no-repeat;
  }

  &__upload {
    display: inline-flex;
    justify-content: center;
    align-items: center;
    position: absolute;
    right: 0;
    bottom: 0;
    width: 26px;
    height: 26px;
    color: $blue;
    border-radius: 50%;
    background-color: #fff;
  }
}

.o-wechat {
  display: inline-block;
  width: 32px;
  height: 32px;
  background: url("~@/assets/icon_wechat.png") 0 0 / 100% 100% no-repeat;
}

.c-wechat {
  border-radius: $radius;
  background-color: #fff;

  &__wrapper {
    position: relative;
    width: 240px;
    height: 240px;

    &.retry::after {
      content: "点击重试";
      display: inline-flex;
      justify-content: center;
      align-items: center;
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      color: $black;
      font-weight: bold;
      background-color: rgba(#fff, 0.8);
      cursor: pointer;
    }
  }

  &__qr {
    display: inline-block;
    width: 100%;
    height: 100%;
  }
}
</style>
