<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,
    },
  ],
  [
    {
      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' },
          ring: '',
          divide: 'divide-y divide-gray-100 dark:divide-gray-800',
        }"
        class="flex flex-col flex-1"
      >
        <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>

        <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>

              <UForm class="flex justify-between gap-4">
                <UFormGroup
                  label="到期时间"
                  class="flex-1"
                >
                  <!-- <UInput
                    v-model="userBalanceState.expire_time"
                    type="datetime"
                  /> -->
                  <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>
              </UForm>

              <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="flex w-full justify-end pb-4">
          <UButton
            icon="tabler:plus"
            size="xs"
            @click="isDigitalSelectorOpen = true"
          >
            新增授权
          </UButton>
        </div> -->
        <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>
      </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>
