import { defineStore } from 'pinia'
import { computed, ref } from 'vue'
import { achievementsApi, notificationsApi, usersApi } from '@/api'
import { mapApiAchievement, mapApiCoinTransaction, mapApiNotification } from '@/api/mappers'
import type { UserStatsDto } from '@/api/types'
import type { Achievement, CoinTransaction, Notification } from '@/types'
import { useAuthStore } from './auth'

export const useUserStore = defineStore('user', () => {
  const achievements = ref<Achievement[]>([])
  const notifications = ref<Notification[]>([])
  const coinHistory = ref<CoinTransaction[]>([])
  const loading = ref(false)
  const error = ref<string | null>(null)
  const activeEnrollments = computed(() => useAuthStore().user?.activeEnrollments ?? 0)
  const enrollmentSlotLimit = computed(() => useAuthStore().user?.enrollmentSlotLimit ?? 0)
  const hasEnrollmentSlotAvailable = computed(
    () => enrollmentSlotLimit.value === 0 || activeEnrollments.value < enrollmentSlotLimit.value,
  )

  function applyStats(stats: UserStatsDto) {
    const auth = useAuthStore()
    if (!auth.user) return

    auth.setUser({
      ...auth.user,
      coins: stats.coins,
      level: stats.level,
      xp: stats.xp,
      currentLevelXp: stats.currentLevelXp,
      nextLevelXp: stats.nextLevelXp,
      lecturesAttended: stats.attendedLectures,
      hoursLearned: Math.round(stats.attendedLectures * 1.5 * 10) / 10,
      achievements: Array.from({ length: stats.achievementsCount }, (_, index) =>
        String(index + 1),
      ),
      activeEnrollments: stats.activeEnrollments,
      enrollmentSlotLimit: stats.enrollmentSlotLimit,
      enrollmentSlotRules: stats.enrollmentSlotRules,
    })
  }

  async function fetchStats() {
    error.value = null
    try {
      const stats = await usersApi.myStats()
      applyStats(stats)
      return stats
    } catch (err) {
      error.value = err instanceof Error ? err.message : 'Не удалось загрузить статистику профиля.'
      throw err
    }
  }

  function adjustActiveEnrollments(delta: number) {
    const auth = useAuthStore()
    if (!auth.user || typeof auth.user.activeEnrollments !== 'number') return

    auth.setUser({
      ...auth.user,
      activeEnrollments: Math.max(auth.user.activeEnrollments + delta, 0),
    })
  }

  async function fetchStudentData() {
    const auth = useAuthStore()
    if (!auth.user) return

    loading.value = true
    error.value = null
    try {
      const [stats, achievementPayload, transactions] = await Promise.all([
        usersApi.myStats(),
        usersApi.myAchievements(),
        usersApi.myTransactions(),
      ])
      const [achievementCatalog, notificationPayload] = await Promise.all([
        achievementsApi.list(),
        notificationsApi.list(),
      ])

      applyStats(stats)
      const unlocked = new Map(
        achievementPayload.map((item) => {
          const achievement = mapApiAchievement(item)
          return [achievement.id, achievement]
        }),
      )
      const catalogIds = new Set(achievementCatalog.map((item) => String(item.id)))
      const lockedAndUnlocked = achievementCatalog.map((item) => {
        const achievement = mapApiAchievement(item)
        return unlocked.get(achievement.id) ?? achievement
      })
      const unlockedOutsideCatalog = achievementPayload
        .map(mapApiAchievement)
        .filter((item) => !catalogIds.has(item.id))

      achievements.value = [...lockedAndUnlocked, ...unlockedOutsideCatalog].sort(
        (a, b) => Number(a.id) - Number(b.id),
      )
      coinHistory.value = transactions.map(mapApiCoinTransaction)
      notifications.value = notificationPayload.map(mapApiNotification)
    } catch (err) {
      error.value = err instanceof Error ? err.message : 'Не удалось загрузить данные профиля.'
    } finally {
      loading.value = false
    }
  }

  async function fetchNotifications() {
    const payload = await notificationsApi.list()
    notifications.value = payload.map(mapApiNotification)
  }

  async function markAllRead() {
    await notificationsApi.markAllRead()
    notifications.value.forEach((n) => (n.read = true))
  }

  const unreadCount = () => notifications.value.filter((n) => !n.read).length

  return {
    achievements,
    notifications,
    coinHistory,
    loading,
    error,
    activeEnrollments,
    enrollmentSlotLimit,
    hasEnrollmentSlotAvailable,
    fetchStats,
    adjustActiveEnrollments,
    fetchStudentData,
    fetchNotifications,
    markAllRead,
    unreadCount,
  }
})
