<template>
  <div>
    <template v-if="ready">
      <el-tabs
        :value="active"
        class="c-tabs has-bottom-padding"
        @tab-click="onTabClick"
      >
        <el-tab-pane
          label="凭证"
          name="Credentials"
        />
        <el-tab-pane
          label="分组"
          name="Group"
        />
        <el-tab-pane
          label="角色"
          name="Role"
        />
      </el-tabs>
      <template v-if="active === 'Credentials'">
        <div class="c-grid-form">
          <label class="c-grid-form__label c-grid-form__auto u-bold">启用</label>
          <div class="l-flex--row">
            <div
              class="c-switch"
              :class="{ checked: user.enabled }"
              @click="onToggleEnable"
            >
              <span class="c-switch__inner">
                <span class="c-switch__active">ON</span>
                <span class="c-switch__inactive">OFF</span>
              </span>
              <span class="c-switch__switch" />
            </div>
          </div>
          <template v-if="credentials && credentials.otp">
            <label class="c-grid-form__label c-grid-form__auto u-bold">OTP</label>
            <div>
              <el-button
                type="danger"
                size="small"
                @click="onResetOTP"
              >
                重置
              </el-button>
            </div>
          </template>
          <label class="c-grid-form__label c-grid-form__auto u-bold">密码</label>
          <div>
            <el-button
              type="danger"
              size="small"
              @click="onResetPassword"
            >
              重置
            </el-button>
          </div>
          <label />
          <div class="has-top-padding">
            <el-button
              type="danger"
              size="small"
              @click="onDel"
            >
              注销
            </el-button>
          </div>
        </div>
      </template>
      <template v-if="active === 'Group'">
        <el-tree
          ref="tree"
          class="l-flex__auto"
          :data="userGroups"
          node-key="path"
          :props="treeProps"
          :expand-on-click-node="false"
          accordion
          highlight-current
          @node-click="onGroupClick"
        />
        <div class="l-flex__none has-top-padding">
          <el-button
            type="danger"
            size="small"
            :disabled="!groupChanged"
            @click="onSaveGroup"
          >
            保存
          </el-button>
        </div>
      </template>
      <template v-if="active === 'Role'">
        <el-transfer
          v-model="role.roles"
          class="c-transfer"
          :titles="['可选', '已分配']"
          :props="{ key: 'id', label: 'description' }"
          :data="role.available"
        />
        <div class="l-flex__none has-top-padding">
          <el-button
            type="danger"
            size="small"
            :disabled="!roleChanged"
            @click="onSaveRole"
          >
            保存
          </el-button>
        </div>
      </template>
    </template>
    <div
      v-else
      class="u-text-center"
    >
      <div
        v-if="ignore"
        class="u-bold"
      >
        您暂无设置该账号的权限
      </div>
      <warning
        v-if="error"
        @click="getSettings"
      />
    </div>
  </div>
</template>

<script>
import { mapGetters } from 'vuex'
import {
  updateUser,
  deleteUser,
  getUserGroups,
  getUserCredentials,
  resetPassword,
  deleteUserCredentials,
  moveUserGroup,
  getUserRoleMapping,
  updateUserRoles
} from '@/api/user'
import {
  unbindDevices,
  updateBindDevices
} from '@/api/device'
import { Role } from '@/constant'

export default {
  name: 'UserSettings',
  props: {
    user: {
      type: Object,
      required: true
    },
    groups: {
      type: Array,
      required: true
    }
  },
  data () {
    return {
      ready: false,
      ignore: false,
      error: false,
      active: 'Credentials',
      credentials: null,
      group: null,
      userGroups: null,
      groupChanged: false,
      role: null,
      treeProps: { children: 'subGroups', label: 'label' }
    }
  },
  computed: {
    ...mapGetters(['isSuperAdmin', 'isTenantAdmin']),
    roleChanged () {
      if (this.role) {
        const { stash, roles } = this.role
        if (stash.length !== roles.length) {
          return true
        }
        if (stash.length !== new Set([...roles, ...stash]).size) {
          return true
        }
      }
      return false
    }
  },
  mounted () {
    this.$nextTick(() => {
      this.getSettings()
    })
  },
  methods: {
    async getSettings () {
      const loading = this.$showLoading()
      this.ready = false
      this.error = false
      try {
        if (!this.role) {
          const { roles, available } = await getUserRoleMapping(this.user.id)

          const superAdmin = roles.find(({ name }) => name === Role.SUPER_ADMIN)
          if (superAdmin && !this.isSuperAdmin) {
            this.ignore = true
            this.$closeLoading(loading)
            return
          }

          const tenantAdmin = roles.find(({ name }) => name === Role.ADMIN)
          if (tenantAdmin && !this.isSuperAdmin) {
            this.ignore = true
            this.$closeLoading(loading)
            return
          }

          const roleKeys = roles.map(({ id }) => id)
          this.role = {
            available,
            roles: roleKeys,
            stash: [...roleKeys]
          }
        }
        if (!this.credentials) {
          const credentials = await getUserCredentials(this.user)
          this.credentials = {
            otp: credentials.find(({ type }) => type === 'otp')
          }
        }
        if (!this.group) {
          const groups = await getUserGroups(this.user.id)
          this.group = this.findLastGroup(groups)
          this.userGroups = this.getRootGroups(this.group)
        }
        this.ready = true
      } catch (e) {
        console.log(e)
        this.error = true
      }
      this.$closeLoading(loading)
    },
    onTabClick (tab) {
      if (this.active !== tab.name) {
        switch (tab.name) {
          case 'Group':
            this.expandTree()
            break
          default:
            break
        }
        this.active = tab.name
      }
    },
    onToggleEnable () {
      const enabled = !this.user.enabled
      updateUser(
        this.user.id,
        { enabled },
        enabled ? '启用' : '禁用'
      ).then(() => {
        this.user.enabled = enabled
      })
    },
    onResetPassword () {
      this.$confirm(
        `将${this.user.username}的密码重置为默认密码？`,
        { type: 'warning' }
      ).then(() => {
        resetPassword(this.user)
      })
    },
    onResetOTP () {
      this.$confirm(
        `将${this.user.username}当前绑定的OTP重置？`,
        { type: 'warning' }
      ).then(() => {
        deleteUserCredentials(this.user.id, this.credentials.otp.id).then(() => {
          this.credentials.otp = null
        })
      })
    },
    onDel () {
      this.$confirm(
        `注销账号${this.user.username}？`,
        { type: 'warning' }
      ).then(() => {
        const loading = this.$showLoading()
        unbindDevices({ user: this.user.id })
          .then(() => deleteUser(this.user))
          .then(() => this.$emit('del'))
          .finally(() => {
            this.$closeLoading(loading)
          })
      })
    },
    onGroupClick (group) {
      this.$group = group
      this.groupChanged = this.$group.path !== this.group.path
    },
    expandTree () {
      this.$nextTick(() => {
        this.$refs.tree.setCurrentKey(this.group.path)
        let parentGroup = this.group.parentGroup
        while (parentGroup) {
          this.$refs.tree.getNode(parentGroup.path).expanded = true
          parentGroup = parentGroup.parentGroup
        }
      })
    },
    getRootGroups (group) {
      let target = group
      while (target.parentGroup) {
        target = target.parentGroup
      }
      return [target]
    },
    findLastGroup (groups) {
      let result = { subGroups: this.groups }
      groups.forEach(({ path }) => {
        if (result) {
          result = result.subGroups.find(group => group.path === path)
        }
      })
      return result
    },
    onSaveGroup () {
      if (!this.groupChanged) {
        return
      }
      if (!this.$group) {
        this.$message({
          type: 'warning',
          message: '请选择用户所属的分组'
        })
        return
      }
      this.$confirm(
        `将${this.user.username}移动至${this.$group.label}？`,
        { type: 'warning' }
      ).then(() => {
        const loading = this.$showLoading()
        updateBindDevices(this.user.id, this.$group.path).then(() => {
          moveUserGroup(this.user.id, this.group, this.$group).then(
            () => {
              this.$closeLoading(loading)
              this.group = this.$group
              this.$group = null
              this.$message({
                type: 'success',
                message: '修改成功'
              })
              this.$emit('group', this.group)
            },
            () => {
              this.group = null
              this.groupChanged = false
              this.getSettings().then(() => {
                if (!this.error) {
                  this.expandTree()
                }
              })
            }
          )
        })
      })
    },
    onSaveRole () {
      if (!this.roleChanged) {
        return
      }
      const { available, stash, roles } = this.role
      const loading = this.$showLoading()
      updateUserRoles(this.user.id, available, stash, roles).then(
        () => {
          this.$closeLoading(loading)
          this.$message({
            type: 'success',
            message: '修改成功'
          })
        },
        () => {
          this.ready = false
          this.role = null
          this.getSettings()
        }
      )
    }
  }
}
</script>

<style lang="scss" scoped>
.c-switch {
  display: inline-block;
  position: relative;
  width: 62px;
  border: 1px solid #bbb;
  border-radius: 2px;
  overflow: hidden;
  cursor: pointer;

  &.checked {
    .c-switch__inner {
      margin-left: 0;
    }

    .c-switch__switch {
      right: 0;
    }
  }

  &__inner {
    display: block;
    margin-left: -100%;
    transition: margin 0.3s ease-in 0s;
    width: 200%;

    & > span {
      float: left;
      width: 50%;
      height: 24px;
      font-size: 12px;
      font-weight: bold;
      line-height: 24px;
    }
  }

  &__active {
    padding-left: 10px;
    color: #ffffff;
    background-image: linear-gradient(to bottom, #00a9ec 0%, #009bd3 100%);
  }

  &__inactive {
    padding-right: 10px;
    color: #4d5258;
    text-align: right;
    background-image: linear-gradient(to bottom, #fefefe 0%, #e8e8e8 100%);
  }

  &__switch {
    position: absolute;
    top: 0;
    bottom: 0;
    width: 23px;
    right: 39px;
    margin: 0;
    border-radius: 2px;
    transition: all 0.3s ease-in 0s;
    border: 1px solid #aaa;
    background-image: linear-gradient(to bottom, #fafafa 0%, #ededed 100%);
  }
}

.c-transfer {
  display: flex;
  width: 100%;

  ::v-deep {
    .el-transfer__panel {
      flex: 1 1 0;
      min-width: 0;
      width: auto;
    }

    .el-transfer__buttons {
      flex: none;
      display: flex;
      justify-content: center;
      align-items: center;
    }

    .el-transfer__button:first-child {
      margin: 0;
    }
  }
}
</style>
