<script lang="ts" setup>
const toast = useToast()
const dayjs = useDayjs()
const loginState = useLoginState()

const systemServices: ServiceType[] = [
  {
    tag: 'PPTToVideo',
    name: '微课视频(PPT驱动)',
  },
  {
    tag: 'TextToVideo',
    name: '绿幕视频(文字驱动)',
  },
  {
    tag: 'SparkChat15',
    name: '讯飞星火大模型 1.5',
  },
  {
    tag: 'SparkChat30',
    name: '讯飞星火大模型 3.0',
  },
  {
    tag: 'SparkChat35',
    name: '讯飞星火大模型 3.5',
  },
  {
    tag: 'TenImgToImg',
    name: '腾讯混元 - 图生图',
  },
  {
    tag: 'TenTextToImg',
    name: '腾讯混元 - 文生图',
  },
]

const columns = [
  {
    key: 'id',
    label: 'ID',
    disabled: true,
  },
  {
    key: 'avatar',
    label: '头像',
    disabled: true,
  },
  {
    key: 'username',
    label: '账户名/姓名',
    disabled: true,
  },
  {
    key: 'company',
    label: '单位',
  },
  {
    key: 'mobile',
    label: '手机号',
  },
  {
    key: 'sex',
    label: '性别',
  },
  {
    key: 'auth_code',
    label: '角色',
  },
  {
    key: 'actions',
    label: '操作',
  },
]

const selectedColumns = ref([
  ...columns.filter((row) => {
    return !['auth_code'].includes(row.key)
  }),
])
const page = ref(1)
const pageCount = ref(15)
const state_filter = ref<'verified' | 'unverified'>('verified')
const is_verified = ref(true)
const viewingUser = ref<UserSchema | null>(null)
const isSlideOpen = computed({
  get: () => !!viewingUser.value,
  set: () => (viewingUser.value = null),
})

watch([is_verified, pageCount], () => (page.value = 1))
watch(
  state_filter,
  () => (is_verified.value = state_filter.value === 'verified')
)

const {
  data: usersData,
  refresh: refreshUsersData,
  status: usersDataStatus,
} = useAsyncData(
  'systemUsers',
  () =>
    useFetchWrapped<
      req.user.UserList & AuthedRequest,
      BaseResponse<PagedData<UserSchema>>
    >('App.User_User.ListUser', {
      token: loginState.token!,
      user_id: loginState.user.id!,
      page: page.value,
      perpage: pageCount.value,
      is_verify: is_verified.value,
    }),
  {
    watch: [page, pageCount, is_verified],
    transform: (res) => {
      res.data.items.unshift(loginState.user)
      return res
    },
  }
)

const isDigitalSelectorOpen = ref(false)
const dhPage = ref(1)
const dhPageCount = ref(10)

watch(dhPageCount, () => (dhPage.value = 1))

const {
  data: digitalHumansData,
  refresh: refreshDigitalHumansData,
  status: digitalHumansDataStatus,
} = useAsyncData(
  'currentUserDigitalHumans',
  () =>
    useFetchWrapped<
      PagedDataRequest & AuthedRequest,
      BaseResponse<PagedData<DigitalHumanItem>>
    >('App.User_UserDigital.GetList', {
      token: loginState.token!,
      user_id: loginState.user.id!,
      to_user_id: viewingUser.value?.id || 0,
      page: dhPage.value,
      perpage: dhPageCount.value,
    }),
  {
    watch: [viewingUser, dhPage, dhPageCount],
  }
)

const {
  data: userBalances,
  status: userBalancesStatus,
  refresh: refreshUserBalances,
} = useAsyncData(
  'userServiceBalances',
  () =>
    useFetchWrapped<
      PagedDataRequest & AuthedRequest,
      BaseResponse<PagedData<ServiceBalance>>
    >('App.User_UserBalance.GetList', {
      token: loginState.token!,
      user_id: loginState.user.id,
      to_user_id: viewingUser.value?.id || 0,
      page: 1,
      perpage: 20,
    }),
  {
    watch: [viewingUser],
  }
)

const getBalanceByTag = (tag: ServiceTag): ServiceBalance | null => {
  return (
    userBalances?.value?.data.items.find((row) => row.request_type === tag) ||
    null
  )
}

const items = (row: UserSchema) => [
  [
    {
      label: '服务和用量',
      icon: 'tabler:server-cog',
      click: () => openSlide(row),
      disabled: row.auth_code === 0,
    },
  ],
  [
    {
      disabled: row.id === loginState.user.id,
      label: row.auth_code !== 0 ? '停用账号' : '启用账号',
      icon: row.auth_code !== 0 ? 'tabler:cancel' : 'tabler:shield-check',
      click: () => setUserStatus(row.id, row.auth_code === 0),
    },
  ],
]

const openSlide = (user: UserSchema) => {
  viewingUser.value = user
}

const closeSlide = () => {
  viewingUser.value = null
}

const onDigitalHumansSelected = (digitalHumans: DigitalHumanItem[]) => {
  useFetchWrapped<
    {
      to_user_id: number
      digital_human_array: number[]
    } & AuthedRequest,
    BaseResponse<{
      total: number
      success: number
      failed: number
    }>
  >('App.User_UserDigital.CreateConnArr', {
    token: loginState.token!,
    user_id: loginState.user.id!,
    to_user_id: viewingUser.value?.id || 0,
    digital_human_array: digitalHumans.map(
      (row) => row.id || row.digital_human_id
    ),
  }).then((res) => {
    if (res.ret === 200) {
      toast.add({
        title: '授权成功',
        description: `成功授权 ${res.data.success} 个数字人${
          res.data.failed ? `，失败 ${res.data.failed} 个` : ''
        }`,
        color: 'green',
        icon: 'tabler:check',
      })
      refreshDigitalHumansData()
    } else {
      toast.add({
        title: '授权失败',
        description: res.msg || '未知错误',
        color: 'red',
        icon: 'tabler:alert-triangle',
      })
    }
  })
}

const revokeDigitalHuman = (uid: number, digitalHumanId: number) => {
  useFetchWrapped<
    {
      to_user_id: number
      digital_human_id: number
    } & AuthedRequest,
    BaseResponse<{
      code: number // 1: success, 0: failed
    }>
  >('App.User_UserDigital.DeleteConn', {
    token: loginState.token!,
    user_id: loginState.user.id!,
    to_user_id: uid,
    digital_human_id: digitalHumanId,
  }).then((res) => {
    if (res.ret === 200 && res.data.code === 1) {
      toast.add({
        title: '撤销成功',
        description: '已撤销数字人授权',
        color: 'green',
        icon: 'tabler:check',
      })
      refreshDigitalHumansData()
    } else {
      toast.add({
        title: '撤销失败',
        description: res.msg || '未知错误',
        color: 'red',
        icon: 'tabler:alert-triangle',
      })
    }
  })
}

const setUserStatus = (uid: number, is_verified: boolean) => {
  useFetchWrapped<
    {
      to_user_id: number
      is_verify: boolean
    } & AuthedRequest,
    BaseResponse<{
      status: number // 1: success, 0: failed
    }>
  >('App.User_User.SetUserVerify', {
    token: loginState.token!,
    user_id: loginState.user.id!,
    to_user_id: uid,
    is_verify: is_verified,
  }).then((res) => {
    if (res.ret === 200 && res.data.status === 1) {
      toast.add({
        title: '操作成功',
        description: `已${is_verified ? '启用' : '停用'}账号`,
        color: 'green',
        icon: is_verified ? 'tabler:shield-check' : 'tabler:cancel',
      })
      refreshUsersData()
    } else {
      toast.add({
        title: '操作失败',
        description: res.msg || '未知错误',
        color: 'red',
        icon: 'tabler:alert-triangle',
      })
    }
  })
}

const userBalanceEditing = ref(false)
const userBalanceState = reactive({
  expire_time: dayjs().add(1, 'month').unix() * 1000,
  remain_count: 1800,
  request_type: '',
})

const isActivateBalance = ref(false)

const isBalanceEditModalOpen = computed({
  get: () => !!viewingUser && userBalanceEditing.value,
  set: (val) => {
    userBalanceEditing.value = val
    if (!val) {
      userBalanceState.expire_time = dayjs().add(1, 'month').unix() * 1000
      userBalanceState.remain_count = 1800
    }
  },
})

const udpateBalance = (tag: ServiceTag, isActivate: boolean = false) => {
  useFetchWrapped<
    {
      to_user_id: number
      request_type: ServiceTag
      expire_time: number
      remain_count: number
    } & AuthedRequest,
    BaseResponse<{
      code: number // 1: success, 0: failed
      data_id?: number
    }>
  >(
    isActivate ? 'App.User_UserBalance.Insert' : 'App.User_UserBalance.Update',
    {
      token: loginState.token!,
      user_id: loginState.user.id!,
      to_user_id: viewingUser.value?.id || 0,
      request_type: tag,
      expire_time: userBalanceState.expire_time / 1000,
      remain_count: userBalanceState.remain_count,
    }
  )
    .then((res) => {
      if (res.ret === 200 && (res.data.code === 1 || !!res.data.data_id)) {
        toast.add({
          title: '操作成功',
          description: `已${isActivate ? '开通' : '更新'}服务`,
          color: 'green',
          icon: 'tabler:check',
        })
      } else {
        toast.add({
          title: '操作失败',
          description: res.msg || '未知错误',
          color: 'red',
          icon: 'tabler:alert-triangle',
        })
      }
    })
    .catch((err) => {
      toast.add({
        title: '操作失败',
        description: err.message || '未知错误',
        color: 'red',
        icon: 'tabler:alert-triangle',
      })
    })
    .finally(() => {
      refreshUserBalances()
      isBalanceEditModalOpen.value = false
    })
}
</script>

<template>
  <LoginNeededContent need-admin>
    <div class="p-4">
      <BubbleTitle
        bubble-color="amber-500"
        subtitle="User Management"
        title="用户管理"
      >
        <template #action>
          <UButton
            color="amber"
            icon="tabler:reload"
            variant="soft"
            @click="refreshUsersData"
          >
            刷新
          </UButton>
        </template>
      </BubbleTitle>
      <GradientDivider
        line-gradient-from="amber"
        line-gradient-to="amber"
      />
      <div>
        <div class="flex justify-between items-center w-full py-3">
          <div class="flex items-center gap-1.5">
            <span class="text-sm leading-0">每页显示:</span>
            <USelect
              v-model="pageCount"
              :options="[5, 10, 15, 20]"
              class="me-2 w-20"
              size="xs"
            />
          </div>

          <div class="flex gap-1.5 items-center">
            <USelectMenu
              v-model="state_filter"
              :options="[
                {
                  label: '正常账号',
                  value: 'verified',
                  icon: 'tabler:user-check',
                },
                {
                  label: '停用账号',
                  value: 'unverified',
                  icon: 'tabler:user-cancel',
                },
              ]"
              :ui-menu="{
                width: 'w-fit',
                option: { size: 'text-xs', icon: { base: 'w-4 h-4' } },
              }"
              size="xs"
              value-attribute="value"
            />
            <USelectMenu
              v-model="selectedColumns"
              :options="columns.filter((row) => !['actions'].includes(row.key))"
              :ui-menu="{
                width: 'w-fit',
                option: { size: 'text-xs', icon: { base: 'w-4 h-4' } },
              }"
              multiple
            >
              <UButton
                color="gray"
                icon="tabler:layout-columns"
                size="xs"
              >
                显示列
              </UButton>
            </USelectMenu>
          </div>
        </div>
        <UTable
          :columns="selectedColumns"
          :loading="usersDataStatus === 'pending'"
          :progress="{ color: 'amber', animation: 'carousel' }"
          :rows="usersData?.data.items"
          class="border dark:border-neutral-800 rounded-md"
        >
          <template #username-data="{ row }">
            <span
              :class="{
                'font-semibold text-amber-500': row.id === loginState.user.id,
              }"
            >
              {{ row.username }}
              <span class="text-xs">
                {{ row.id === loginState.user.id ? ' (本账号)' : '' }}
              </span>
            </span>
          </template>
          <template #avatar-data="{ row }">
            <UAvatar
              :alt="row.username.toUpperCase()"
              :src="row.avatar"
              size="sm"
            />
          </template>
          <template #sex-data="{ row }">
            {{ row.sex === 0 ? '' : row.sex === 1 ? '男' : '女' }}
          </template>
          <template #actions-data="{ row }">
            <UDropdown :items="items(row)">
              <UButton
                color="gray"
                icon="tabler:dots"
                variant="ghost"
              />
            </UDropdown>
          </template>
        </UTable>
        <div class="flex justify-end py-3.5">
          <UPagination
            v-if="(usersData?.data.total || -1) > 0"
            v-model="page"
            :page-count="pageCount"
            :total="usersData?.data.total || 0"
          />
        </div>
      </div>
    </div>
    <USlideover
      v-model="isSlideOpen"
      :ui="{ width: 'w-screen max-w-3xl' }"
    >
      <UCard
        :ui="{
          body: { base: 'flex-1 overflow-y-auto' },
          ring: '',
          divide: 'divide-y divide-gray-100 dark:divide-gray-800',
        }"
        class="flex flex-col overflow-hidden"
      >
        <template #header>
          <UButton
            class="flex absolute end-5 top-5 z-10"
            color="gray"
            icon="tabler:x"
            padded
            size="sm"
            square
            variant="ghost"
            @click="closeSlide"
          />
          服务和用量管理
          <p class="text-sm font-medium text-primary">
            {{ viewingUser?.username }} (UID:{{ viewingUser?.id }})
          </p>
        </template>

        <div class="">
          <UDivider
            label="服务用量管理"
            class="mb-4"
            :ui="{ label: 'text-primary-500 dark:text-primary-400' }"
          />

          <div class="border dark:border-neutral-700 rounded-md">
            <UTable
              :columns="[
                { key: 'service', label: '服务' },
                { key: 'status', label: '状态' },
                { key: 'create_time', label: '开通时间' },
                { key: 'expire_time', label: '过期时间' },
                { key: 'remain_count', label: '余量(秒)' },
                { key: 'actions' },
              ]"
              :loading="userBalancesStatus === 'pending'"
              :rows="[
                ...systemServices,
                // 如果 userBalances?.data.items 具有 systemServices 中没有的服务，则添加到列表中
                ...(userBalances?.data.items
                  .filter(
                    (row) =>
                      !systemServices.find((s) => s.tag === row.request_type)
                  )
                  .map((row) => ({
                    tag: row.request_type,
                    name: row.request_type,
                  })) || []),
              ]"
            >
              <template #service-data="{ row }: { row: ServiceType }">
                {{
                  systemServices.find((s) => s.tag === row.tag)?.name || row.tag
                }}
              </template>

              <template #status-data="{ row }">
                <UBadge
                  v-if="!getBalanceByTag(row.tag)"
                  color="gray"
                  variant="solid"
                  size="xs"
                >
                  未开通
                </UBadge>
                <UBadge
                  v-else-if="
                  getBalanceByTag(row.tag)!.expire_time < dayjs().unix()
                "
                  color="red"
                  variant="subtle"
                  size="xs"
                >
                  已过期
                </UBadge>
                <UBadge
                  v-else
                  color="green"
                  variant="subtle"
                  size="xs"
                >
                  生效中
                </UBadge>
              </template>

              <template #create_time-data="{ row }">
                <span class="text-xs">
                  {{
                    !!getBalanceByTag(row.tag)
                      ? dayjs(
                          getBalanceByTag(row.tag)!.create_time * 1000
                        ).format('YYYY-MM-DD HH:mm:ss')
                      : '未开通'
                  }}
                </span>
              </template>

              <template #expire_time-data="{ row }">
                <span class="text-xs">
                  {{
                    !!getBalanceByTag(row.tag)
                      ? dayjs(
                          getBalanceByTag(row.tag)!.expire_time * 1000
                        ).format('YYYY-MM-DD HH:mm:ss')
                      : '未开通'
                  }}
                </span>
              </template>

              <template #remain_count-data="{ row }">
                <span class="text-sm">
                  {{ getBalanceByTag(row.tag)?.remain_count || 0 }}
                </span>
              </template>

              <template #actions-data="{ row }">
                <UButton
                  v-if="!getBalanceByTag(row.tag)"
                  color="green"
                  icon="tabler:clock-check"
                  size="xs"
                  variant="soft"
                  @click="
                    () => {
                      isActivateBalance = true
                      userBalanceEditing = true
                      userBalanceState.request_type = row.tag
                    }
                  "
                >
                  开通
                </UButton>
                <UButton
                  v-else-if="getBalanceByTag(row.tag)!.expire_time < dayjs().unix()"
                  color="teal"
                  icon="tabler:clock-plus"
                  size="xs"
                  variant="soft"
                  @click="
                    () => {
                      isActivateBalance = false
                      userBalanceEditing = true
                      userBalanceState.request_type = row.tag
                    }
                  "
                >
                  延续
                </UButton>
                <UButton
                  v-else
                  color="sky"
                  icon="tabler:rotate-clockwise"
                  size="xs"
                  variant="soft"
                  @click="
                  () => {
                    isActivateBalance = false
                    userBalanceEditing = true
                    userBalanceState.request_type = row.tag
                    userBalanceState.expire_time =
                      getBalanceByTag(row.tag)!.expire_time * 1000
                    userBalanceState.remain_count = getBalanceByTag(row.tag)!.remain_count
                  }
                "
                >
                  更新
                </UButton>
              </template>
            </UTable>

            <UModal
              v-model="isBalanceEditModalOpen"
              :ui="{ width: 'w-xl' }"
            >
              <UCard
                :ui="{
                  ring: '',
                  divide: 'divide-y divide-gray-100 dark:divide-gray-800',
                }"
              >
                <template #header>
                  <!-- 为 {{ viewingUser!.username }}
                <span class="text-primary">{{ isActivateBalance ? '开通' : '续期' }}</span>
                服务：
                {{
                  systemServices.find(
                    (s) => s.tag === userBalanceState.request_type
                  )?.name || userBalanceState.request_type
                }} -->
                  <div class="flex justify-between items-center gap-1">
                    <h1 class="text-sm font-medium">
                      {{ isActivateBalance ? '开通' : '续期' }}
                      {{
                        systemServices.find(
                          (s) => s.tag === userBalanceState.request_type
                        )?.name || userBalanceState.request_type
                      }}
                      服务
                    </h1>
                    <p
                      class="text-xs text-indigo-500 inline-flex items-center gap-1"
                    >
                      <UIcon
                        name="tabler:user-circle"
                        class="text-base"
                      />
                      {{ viewingUser!.username }}
                    </p>
                  </div>
                </template>

                <div class="flex justify-between gap-4">
                  <UFormGroup
                    label="到期时间"
                    class="flex-1"
                  >
                    <UPopover :popper="{ placement: 'bottom-start' }">
                      <UButton
                        block
                        variant="soft"
                        icon="i-heroicons-calendar-days-20-solid"
                        :label="
                          dayjs(userBalanceState.expire_time).format(
                            'YYYY-MM-DD HH:mm'
                          )
                        "
                      />

                      <template #panel="{ close }">
                        <DatePicker
                          v-model="userBalanceState.expire_time"
                          locale="cn"
                          mode="dateTime"
                          title-position="left"
                          is-required
                          is24hr
                          @close="close"
                        />
                      </template>
                    </UPopover>
                  </UFormGroup>
                  <UFormGroup
                    label="服务时长(秒)"
                    class="flex-1"
                  >
                    <UInput v-model="userBalanceState.remain_count" />
                  </UFormGroup>
                </div>

                <template #footer>
                  <div class="flex items-center justify-end gap-2">
                    <UButton
                      color="gray"
                      size="sm"
                      variant="ghost"
                      @click="isBalanceEditModalOpen = false"
                    >
                      取消
                    </UButton>
                    <UButton
                      color="primary"
                      icon="tabler:check"
                      size="sm"
                      @click="
                        udpateBalance(
                          userBalanceState.request_type as ServiceTag,
                          isActivateBalance
                        )
                      "
                    >
                      {{ isActivateBalance ? '开通' : '续期' }}
                    </UButton>
                  </div>
                </template>
              </UCard>
            </UModal>
          </div>

          <UDivider
            label="数字人权限管理"
            class="my-4"
            :ui="{ label: 'text-primary-500 dark:text-primary-400' }"
          />

          <div class="border dark:border-neutral-700 rounded-md">
            <UTable
              :columns="[
                { key: 'name', label: '名称' },
                { key: 'digital_human_id', label: '本地ID' },
                { key: 'model_id', label: '上游ID' },
                { key: 'actions' },
              ]"
              :loading="digitalHumansDataStatus === 'pending'"
              :rows="digitalHumansData?.data.items"
            >
              <template #actions-data="{ row }">
                <UButton
                  color="gray"
                  icon="tabler:cancel"
                  size="xs"
                  variant="ghost"
                  @click="
                    revokeDigitalHuman(
                      viewingUser?.id || 0,
                      row.digital_human_id
                    )
                  "
                >
                  撤销授权
                </UButton>
              </template>
            </UTable>
          </div>
          <div class="flex justify-between py-3.5">
            <UButton
              icon="tabler:plus"
              size="xs"
              @click="isDigitalSelectorOpen = true"
            >
              新增授权
            </UButton>
            <UPagination
              v-if="(digitalHumansData?.data.total || -1) > 0"
              v-model="dhPage"
              :page-count="dhPageCount"
              :total="digitalHumansData?.data.total || 0"
            />
          </div>
        </div>
      </UCard>
      <ModalDigitalHumanSelect
        :disabled-digital-human-ids="
          digitalHumansData?.data.items.map((d) => d.model_id)
        "
        :is-open="isDigitalSelectorOpen"
        default-tab="system"
        multiple
        @close="isDigitalSelectorOpen = false"
        @select="digitalHumans => onDigitalHumansSelected(digitalHumans as DigitalHumanItem[])"
      />
    </USlideover>
  </LoginNeededContent>
</template>

<style scoped></style>
