import { Capacitor, registerPlugin } from '@capacitor/core'
import type { Router } from 'vue-router'
import http from '../api/http'

interface WidgetItem {
  title: string
  subtitle: string
  time: string
}

interface WidgetPayload {
  displayName: string
  scheduleDate: string
  schedule: WidgetItem[]
  exams: WidgetItem[]
  updatedAt: string
}

interface NativeHomePlugin {
  updateWidgets(options: { payload: WidgetPayload }): Promise<void>
  clearWidgets(): Promise<void>
  getLaunchRoute(): Promise<{ route?: string }>
}

interface StoredUser {
  displayName?: string
  roles?: string[]
}

const NativeHome = registerPlugin<NativeHomePlugin>('NativeHome')
const native = Capacitor.isNativePlatform()
const syncInterval = 10 * 60 * 1000
let lastSyncAt = 0
let syncPromise: Promise<void> | null = null

function storedUser(): StoredUser | null {
  try {
    const value = localStorage.getItem('jiaowu_user')
    return value ? JSON.parse(value) as StoredUser : null
  } catch {
    return null
  }
}

function dateKey(date: Date) {
  const year = date.getFullYear()
  const month = String(date.getMonth() + 1).padStart(2, '0')
  const day = String(date.getDate()).padStart(2, '0')
  return `${year}-${month}-${day}`
}

function parseDateOnly(value?: string) {
  if (!value) return null
  const [year, month, day] = value.slice(0, 10).split('-').map(Number)
  return year && month && day ? new Date(year, month - 1, day) : null
}

function slotTime(slots: any[], period: number, field: 'startsAt' | 'endsAt') {
  return slots.find((slot) => slot.periodNumber === period)?.[field]?.slice(0, 5) ?? ''
}

function activeWeek(timetable: any, now: Date) {
  const start = parseDateOnly(timetable?.term?.startDate)
  const end = parseDateOnly(timetable?.term?.endDate)
  if (!start || !end || now < start || now > new Date(end.getTime() + 86400000)) return null
  const mondayOffset = start.getDay() === 0 ? 6 : start.getDay() - 1
  const firstMonday = new Date(start)
  firstMonday.setDate(firstMonday.getDate() - mondayOffset)
  return Math.floor((now.getTime() - firstMonday.getTime()) / 604800000) + 1
}

function scheduleItems(timetable: any, now: Date): WidgetItem[] {
  const week = activeWeek(timetable, now)
  if (!week) return []
  const weekday = now.getDay() || 7
  return (timetable?.entries ?? [])
    .filter((entry: any) =>
      entry.dayOfWeek === weekday &&
      week >= entry.startWeek &&
      week <= entry.endWeek &&
      (entry.weekPattern === 'All' ||
        (entry.weekPattern === 'Odd' && week % 2 === 1) ||
        (entry.weekPattern === 'Even' && week % 2 === 0)))
    .sort((left: any, right: any) => left.startPeriod - right.startPeriod)
    .slice(0, 3)
    .map((entry: any) => {
      const endPeriod = entry.startPeriod + entry.periodCount - 1
      const startsAt = slotTime(timetable.slots ?? [], entry.startPeriod, 'startsAt')
      const endsAt = slotTime(timetable.slots ?? [], endPeriod, 'endsAt')
      return {
        title: String(entry.courseName ?? '未命名课程'),
        subtitle: [entry.buildingName, entry.classroomName].filter(Boolean).join(' · ') || '地点待定',
        time: startsAt && endsAt ? `${startsAt}—${endsAt}` : `第 ${entry.startPeriod}—${endPeriod} 节`,
      }
    })
}

function examItems(exams: any[], now: Date): WidgetItem[] {
  return exams
    .map((exam) => {
      const startsAt = new Date(exam.startsAt)
      const date = Number.isNaN(startsAt.getTime())
        ? parseDateOnly(exam.examDate)
        : startsAt
      return { exam, date }
    })
    .filter(({ date }) => date && date.getTime() >= new Date(
      now.getFullYear(), now.getMonth(), now.getDate(),
    ).getTime())
    .sort((left, right) => left.date!.getTime() - right.date!.getTime())
    .slice(0, 3)
    .map(({ exam, date }) => ({
      title: String(exam.courseName ?? '未命名考试'),
      subtitle: [
        exam.buildingName,
        exam.classroomName,
        exam.seatNumber ? `${exam.seatNumber} 号座` : '',
      ].filter(Boolean).join(' · ') || '考场待定',
      time: `${date!.getMonth() + 1}/${date!.getDate()} ${
        Number.isNaN(new Date(exam.startsAt).getTime())
          ? '时间待定'
          : new Intl.DateTimeFormat('zh-CN', {
              hour: '2-digit',
              minute: '2-digit',
              hour12: false,
            }).format(new Date(exam.startsAt))
      }`,
    }))
}

export async function clearNativeWidgets() {
  if (!native) return
  try {
    await NativeHome.clearWidgets()
  } catch (error) {
    console.warn('清理 Android 桌面组件失败', error)
  }
}

export async function syncNativeWidgets(force = false) {
  if (!native) return
  if (!localStorage.getItem('jiaowu_token')) {
    await clearNativeWidgets()
    return
  }
  if (!force && Date.now() - lastSyncAt < syncInterval) return
  if (syncPromise) return syncPromise

  syncPromise = (async () => {
    const user = storedUser()
    const roles = user?.roles ?? []
    if (!roles.some((role) => role === 'Student' || role === 'Teacher')) {
      await clearNativeWidgets()
      return
    }

    const [timetableResult, examResult] = await Promise.allSettled([
      http.get('/timetables/mine'),
      http.get('/exams/my-schedule'),
    ])
    const now = new Date()
    const payload: WidgetPayload = {
      displayName: user?.displayName?.trim() || '同学',
      scheduleDate: dateKey(now),
      schedule: timetableResult.status === 'fulfilled'
        ? scheduleItems(timetableResult.value.data, now)
        : [],
      exams: examResult.status === 'fulfilled'
        ? examItems(examResult.value.data, now)
        : [],
      updatedAt: now.toISOString(),
    }
    await NativeHome.updateWidgets({ payload })
    lastSyncAt = Date.now()
  })().catch((error) => {
    console.warn('同步 Android 桌面组件失败', error)
  }).finally(() => {
    syncPromise = null
  })

  return syncPromise
}

function routeForShortcut(route: string) {
  const roles = storedUser()?.roles ?? []
  if (route === 'timetable') {
    return roles.some((role) => role === 'Student' || role === 'Teacher')
      ? '/my-timetable'
      : '/class-timetable'
  }
  if (route === 'exams') return '/exams'
  if (route === 'attendance') {
    return roles.includes('Student') ? '/my-attendance' : '/teacher-attendance'
  }
  if (route === 'notifications') return '/notifications'
  return '/dashboard'
}

export function initializeNativeHome(router: Router) {
  if (!native) return

  const openShortcut = (route?: string) => {
    if (!route) return
    if (!localStorage.getItem('jiaowu_token')) {
      sessionStorage.setItem('mingxu_pending_shortcut', route)
      void router.push('/login')
      return
    }
    void router.push(routeForShortcut(route))
  }
  const shortcutListener = (event: Event) => {
    const value = event as CustomEvent<{ route?: string }> & { route?: string }
    const eventRoute = value.detail?.route ?? value.route
    void NativeHome.getLaunchRoute()
      .then(({ route }) => openShortcut(route ?? eventRoute))
      .catch(() => openShortcut(eventRoute))
  }
  window.addEventListener('mingxuShortcut', shortcutListener)
  document.addEventListener('visibilitychange', () => {
    if (!document.hidden) void syncNativeWidgets()
  })
  window.addEventListener('mingxu-auth-changed', () => {
    lastSyncAt = 0
    const pendingShortcut = sessionStorage.getItem('mingxu_pending_shortcut')
    if (localStorage.getItem('jiaowu_token') && pendingShortcut) {
      sessionStorage.removeItem('mingxu_pending_shortcut')
      openShortcut(pendingShortcut)
    }
    void syncNativeWidgets(true)
  })
  router.afterEach(() => {
    void syncNativeWidgets()
  })

  void NativeHome.getLaunchRoute()
    .then(({ route }) => openShortcut(route))
    .catch((error) => console.warn('读取 Android 快捷入口失败', error))
  void syncNativeWidgets()
}
