<script setup lang="ts">
import { Icon } from "@iconify/vue"
import { NH2, NH3 } from "naive-ui"
import { getProfile } from "shared/api"
import { useBreakpoints } from "shared/composables/breakpoints"
import { durationToDays, parseTime } from "utils/functions"
import { Profile, UserBadge as UserBadgeType } from "utils/types"
import { getMetrics, getUserBadges } from "../api"
import GroupedUserBadge from "shared/components/GroupedUserBadge.vue"

const route = useRoute()
const router = useRouter()
const profile = ref<Profile | null>(null)
const problems = ref<string[]>([])
const firstSubmissionAt = ref("")
const latestSubmissionAt = ref("")
const toLatestAt = ref("")
const learnDuration = ref("")
const userBadges = ref<GroupedBadge[]>([])
const [loading, toggle] = useToggle()
const [show, toggleShow] = useToggle(false)

const { isDesktop } = useBreakpoints()

const isDefaultAvatar = computed(
  () => profile.value?.avatar.endsWith("default.png") ?? true,
)

const problemsFlexRef = ref<HTMLElement | null>(null)
const itemsPerRow = ref(8)

function updateItemsPerRow() {
  if (!problemsFlexRef.value) return
  const buttons = problemsFlexRef.value.querySelectorAll("button")
  if (!buttons.length) return
  const firstTop = buttons[0].offsetTop
  let count = 0
  for (const btn of buttons) {
    if (btn.offsetTop === firstTop) count++
    else break
  }
  if (count > 0) itemsPerRow.value = count
}

useResizeObserver(problemsFlexRef, updateItemsPerRow)
watch(problems, async () => {
  await nextTick()
  updateItemsPerRow()
})

const visibleProblems = computed(() =>
  show.value ? problems.value : problems.value.slice(0, itemsPerRow.value * 3),
)

const hasMoreProblems = computed(
  () => problems.value.length > itemsPerRow.value * 3,
)

// 分组徽章接口
interface GroupedBadge {
  icon: string
  count: number
  badges: UserBadgeType[]
  latestEarnedTime: Date
}

// 按图标分组徽章
function groupBadgesByIcon(badges: UserBadgeType[]): GroupedBadge[] {
  const grouped = new Map<string, UserBadgeType[]>()

  // 按图标分组
  badges.forEach((badge) => {
    const icon = badge.badge.icon
    if (!grouped.has(icon)) {
      grouped.set(icon, [])
    }
    grouped.get(icon)!.push(badge)
  })

  // 转换为数组并排序
  return Array.from(grouped.entries())
    .map(([icon, badgeList]) => ({
      icon,
      count: badgeList.length,
      badges: badgeList,
      latestEarnedTime: new Date(
        Math.max(...badgeList.map((b) => new Date(b.earned_time).getTime())),
      ),
    }))
    .sort((a, b) => a.icon.localeCompare(b.icon))
}

async function init() {
  toggle(true)
  try {
    const res = await getProfile(route.query.name as string)
    profile.value = res.data
    const acm = res.data.acm_problems_status.problems || {}
    const oi = res.data.oi_problems_status.problems || {}
    const ac: string[] = []
    for (let problems of [acm, oi]) {
      Object.keys(problems).forEach((id) => {
        if (problems[id]["status"] === 0) {
          ac.push(problems[id]["_id"])
        }
      })
    }
    ac.sort()
    problems.value = ac
    const promises: Promise<{ data: any }>[] = []

    if (profile.value.submission_number > 0) {
      promises.push(getMetrics(profile.value.user.id))
    }

    if (route.query.name) {
      promises.push(getUserBadges(route.query.name as string))
    } else {
      promises.push(getUserBadges())
    }

    const results = await Promise.all(promises)

    // 处理 metrics 结果
    if (profile.value.submission_number > 0) {
      const metricsRes = results[0]
      firstSubmissionAt.value = parseTime(metricsRes.data.first)
      latestSubmissionAt.value = parseTime(metricsRes.data.latest)
      toLatestAt.value = durationToDays(
        metricsRes.data.latest,
        metricsRes.data.now,
      )
      learnDuration.value = durationToDays(
        metricsRes.data.first,
        metricsRes.data.latest,
      )
    }

    // 处理 badges 结果
    userBadges.value = groupBadgesByIcon(results[1].data)
  } finally {
    toggle(false)
  }
}

const metrics = computed(() => {
  if (loading.value) return []
  return [
    {
      icon: "fluent-emoji:face-with-peeking-eye",
      title: learnDuration.value,
      content: "总共学习天数",
    },
    {
      icon: "fluent-emoji:cheese-wedge",
      title: toLatestAt.value,
      content: "距离上次提交",
    },
    {
      icon: "fluent-emoji:dog-face",
      title: latestSubmissionAt.value,
      content: "最新一次提交时间",
    },
    {
      icon: "fluent-emoji:cat-with-wry-smile",
      title: firstSubmissionAt.value,
      content: "第一次提交时间",
    },
    {
      icon: "fluent-emoji:candy",
      title: profile.value?.accepted_number ?? 0,
      content: "已解决的题目数量",
      animate: true,
    },
    {
      icon: "fluent-emoji:thinking-face",
      title: profile.value?.submission_number ?? 0,
      content: "总提交数量",
      animate: true,
    },
  ]
})

onMounted(init)
</script>
<template>
  <n-flex
    class="wrapper"
    vertical
    justify="center"
    align="center"
    v-if="!loading && profile"
  >
    <n-image
      :width="140"
      :height="140"
      :src="profile.avatar"
      :preview-disabled="isDefaultAvatar"
      object-fit="cover"
      :style="{
        borderRadius: '50%',
        overflow: 'hidden',
        cursor: isDefaultAvatar ? 'default' : 'pointer',
      }"
    />
    <h2>{{ profile.user.username }}</h2>
    <p class="desc">{{ profile.mood }}</p>
  </n-flex>

  <n-grid
    v-if="profile && profile.submission_number > 0"
    class="wrapper"
    :cols="2"
    :x-gap="10"
    :y-gap="10"
  >
    <n-gi v-for="item in metrics" :key="item.content">
      <n-card hoverable>
        <n-flex align="center">
          <Icon v-if="isDesktop" :icon="item.icon" width="50" />
          <div>
            <Component :is="isDesktop ? NH2 : NH3" class="number">
              <n-number-animation v-if="item.animate" :to="item.title" />
              <template v-else>
                {{ item.title }}
              </template>
            </Component>
            <n-h4 class="number-label">{{ item.content }}</n-h4>
          </div>
        </n-flex>
      </n-card>
    </n-gi>
  </n-grid>

  <!-- 徽章展示卡片 -->
  <n-card
    v-if="!loading && profile && userBadges.length > 0"
    class="wrapper"
    hoverable
  >
    <template #header>
      <n-h4 style="margin: 0">获得的徽章</n-h4>
    </template>
    <n-flex wrap>
      <GroupedUserBadge
        v-for="groupedBadge in userBadges"
        :key="groupedBadge.icon"
        :grouped-badge="groupedBadge"
      />
    </n-flex>
  </n-card>

  <n-descriptions v-if="!loading && profile" class="wrapper" bordered>
    <n-descriptions-item v-if="!!problems.length">
      <template #label>
        <n-flex justify="space-between" align="center">
          <span>已解决的题目</span>
          <n-button
            text
            type="primary"
            v-if="hasMoreProblems"
            @click="toggleShow(!show)"
          >
            {{ show ? "隐藏全部" : "显示全部" }}
          </n-button>
        </n-flex>
      </template>
      <div ref="problemsFlexRef">
        <n-flex>
          <n-button
            v-for="id in visibleProblems"
            :key="id"
            @click="router.push('/problem/' + id)"
          >
            {{ id }}
          </n-button>
        </n-flex>
      </div>
    </n-descriptions-item>
  </n-descriptions>
  <n-empty v-if="!loading && !profile" description="该用户不存在">
    <template #extra>
      <n-button @click="router.push('/')">返回主页</n-button>
    </template>
  </n-empty>
</template>
<style scoped>
.wrapper {
  max-width: 610px;
  margin: 16px auto 0;
}

.number {
  margin-bottom: 0;
  font-weight: bold;
}

.number-label {
  margin: 0;
}

h2 {
  margin: 0;
  font-weight: normal;
}

.desc {
  margin: 0 auto;
  word-wrap: break-word;
  max-width: 100%;
}
</style>
