import store from '@/store'
import { Role } from '@/constant'
import request, { keycloakRequest } from '@/utils/request'
import {
  send,
  add,
  update,
  messageSend
} from './base'

// 公众号二维码
export function getTicket (id) {
  return request({
    url: `keycloak/query/ticket/${id}`,
    method: 'GET'
  })
}

// 小程序二维码
export function getQrcode (data) {
  return request({
    url: `wxapplet/qrcode`,
    method: 'GET',
    params: data
  })
}

export function userinfo (silence) {
  const config = {
    // url: `${baseUrl}/realms/${realm}/account`,
    url: `/users/${store.getters.userId}`,
    method: 'GET'
  }
  if (silence) {
    config.custom = true
    return keycloakRequest(config)
  }
  return send(config, keycloakRequest)
}

export function addUser (data) {
  return add({
    url: `/users`,
    method: 'POST',
    data
  }, keycloakRequest)
}

export function updateUser (id, data, message) {
  return update({
    url: `/users/${id}`,
    method: 'PUT',
    data
  }, message, keycloakRequest)
}

export function deleteUser ({ id }) {
  return keycloakRequest({
    url: `/users/${id}`,
    method: 'DELETE'
  })
}

export function getUserCredentials ({ id }) {
  return keycloakRequest({
    url: `/users/${id}/credentials`,
    method: 'GET'
  })
}

export function deleteUserCredentials (userId, credentialId) {
  return send({
    url: `/users/${userId}/credentials/${credentialId}`,
    method: 'DELETE'
  }, keycloakRequest)
}

export function resetPassword ({ id }) {
  return messageSend({
    url: `/users/${id}/reset-password`,
    method: 'PUT',
    data: {
      type: 'password',
      value: process.env.VUE_APP_USER_PASSWORD,
      temporary: true
    }
  }, '重置', keycloakRequest)
}

export function getTenantsByQuery (query, onlyOnce) {
  const { pageSize: max, pageNum, name, ...params } = query
  return keycloakRequest({
    url: `/groups`,
    method: 'GET',
    params: {
      briefRepresentation: false,
      max,
      first: pageNum ? (pageNum - 1) * max : void 0,
      search: name || void 0,
      ...params
    }
  }).then(data => {
    return { data: normalizeGroups(data, null, onlyOnce) }
  })
}

function normalizeGroups (groups, parentGroup, onlyOnce) {
  return groups.map(({ id, name, path, attributes, subGroups }) => {
    const remark = attributes.remark?.[0] || ''
    const group = {
      parentGroup,
      id,
      path,
      name,
      remark,
      aiAudit: parentGroup ? void 0 : attributes.aiAudit?.[0] || '0',
      label: remark || name
    }
    if (onlyOnce) {
      return group
    }
    group.subGroups = normalizeGroups(subGroups.sort((a, b) => a.name <= b.name ? -1 : 1), group)
    return group
  })
}

function getTenantCount (name) {
  return keycloakRequest({
    url: `/groups/count`,
    method: 'GET',
    params: {
      top: true,
      search: name || void 0
    }
  })
}

export async function getTenants (query) {
  const { count } = await getTenantCount(query.name)
  const { data } = await getTenantsByQuery(query)
  return {
    data,
    totalCount: count
  }
}

export function getTenantTree () {
  if (store.getters.isSuperAdmin) {
    return getTenantsByQuery({})
  }
  return getGroups().then(data => {
    const groups = normalizeGroups([data])
    groups[0].label = '根部门'
    return { data: groups }
  })
}

export function addTenant ({ name, remark, aiAudit }) {
  return add({
    url: `/groups`,
    method: 'POST',
    data: {
      name,
      attributes: {
        remark: [remark],
        aiAudit: aiAudit ? [aiAudit] : void 0
      }
    }
  }, keycloakRequest)
}

export function getTopGroups () {
  if (store.getters.isSuperAdmin) {
    return getTenantsByQuery({}, true)
  }
  return getGroups().then(data => {
    return { data: normalizeGroups(data.subGroups, true) }
  })
}

async function getGroups () {
  if (!store.getters.tenantId) {
    const groups = await getUserGroups(store.getters.userId)
    store.commit('user/SET_TENANT_ID', groups[0].id)
  }
  return keycloakRequest({
    url: `/groups/${store.getters.tenantId}`,
    method: 'GET'
  })
}

export function addSubGroup ({ id }, { name, remark }) {
  return add({
    url: `/groups/${id}/children`,
    method: 'POST',
    data: {
      name,
      attributes: { remark: [remark] }
    }
  }, keycloakRequest)
}

export function updateGroup ({ id, name, remark, aiAudit }) {
  return update({
    url: `/groups/${id}`,
    method: 'PUT',
    data: {
      name,
      attributes: {
        remark: [remark],
        aiAudit: aiAudit ? [aiAudit] : void 0
      }
    }
  }, null, keycloakRequest)
}

export function deleteGroup ({ id }) {
  return keycloakRequest({
    url: `/groups/${id}`,
    method: 'DELETE'
  })
}

export function getUsersByGroup (query) {
  const { id, pageSize: max, pageNum, ...params } = query
  return keycloakRequest({
    url: `/groups/${id}/members`,
    method: 'GET',
    params: {
      briefRepresentation: true,
      max: max + 1,
      first: pageNum ? (pageNum - 1) * max : void 0,
      ...params
    }
  }).then(data => {
    const totalCount = data.length
    if (totalCount > max) {
      data = data.slice(0, -1)
    }
    return {
      data,
      totalCount
    }
  })
}

export function getUserGroups (id, briefRepresentation = true) {
  return keycloakRequest({
    url: `/users/${id}/groups`,
    method: 'GET',
    params: { briefRepresentation }
  }).then(data => data.sort((a, b) => a.path.length - b.path.length))
}

function addUserToGroup (userId, groupId) {
  return keycloakRequest({
    url: `/users/${userId}/groups/${groupId}`,
    method: 'PUT'
  })
}

function removeUserFromGroup (userId, groupId) {
  return keycloakRequest({
    url: `/users/${userId}/groups/${groupId}`,
    method: 'DELETE'
  })
}

export async function moveUserGroup (userId, from, to) {
  const fromGroups = getGroupList(from)
  const toGroups = getGroupList(to)
  let fromLast = fromGroups.length - 1
  const toLast = toGroups.length - 1
  let start = 0
  while (start <= fromLast && start <= toLast) {
    if (fromGroups[start].id === toGroups[start].id) {
      start += 1
    } else {
      break
    }
  }
  const changed = start <= fromLast || start <= toLast
  for (; fromLast >= start; fromLast--) {
    await removeUserFromGroup(userId, fromGroups[fromLast].id)
  }
  for (; start <= toLast; start++) {
    await addUserToGroup(userId, toGroups[start].id)
  }
  return changed
}

function getGroupList (group) {
  const groups = [group]
  let parentGroup = group.parentGroup
  while (parentGroup) {
    groups.unshift(parentGroup)
    parentGroup = parentGroup.parentGroup
  }
  return groups
}

export function getUserRoleMapping (id) {
  return getUserRoles(id).then(
    roles => getRoles().then(
      available => {
        return {
          available,
          roles
        }
      }
    )
  )
}

function getUserRoles (id) {
  return keycloakRequest({
    url: `/users/${id}/role-mappings/realm`,
    method: 'GET'
  })
}

function getRoles () {
  return keycloakRequest({
    url: `/roles`,
    method: 'GET'
  }).then(filterRoles)
}

function filterRoles (roles) {
  const isSuperAdmin = store.getters.isSuperAdmin
  return roles.filter(({ name }) => name !== Role.SUPER_ADMIN && (isSuperAdmin || name !== Role.ADMIN) && name.startsWith('ROLE_'))
}

export async function updateUserRoles (userId, available, fromKeys, toKeys) {
  const delRoles = []
  const toSet = new Set(toKeys)
  fromKeys.forEach(id => {
    if (!toSet.has(id)) {
      delRoles.push(available.find(role => role.id === id))
    }
  })
  if (delRoles.length) {
    await removeUserRoles(userId, delRoles)
  }
  const addRoles = []
  const fromSet = new Set(fromKeys)
  toKeys.forEach(id => {
    if (!fromSet.has(id)) {
      addRoles.push(available.find(role => role.id === id))
    }
  })
  if (addRoles.length) {
    await addUserRoles(userId, addRoles)
  }
}

function removeUserRoles (userId, roles) {
  return keycloakRequest({
    url: `/users/${userId}/role-mappings/realm`,
    method: 'DELETE',
    data: roles
  })
}

function addUserRoles (userId, roles) {
  return keycloakRequest({
    url: `/users/${userId}/role-mappings/realm`,
    method: 'POST',
    data: roles
  })
}
