import { apiRequest, apiRequestBlob, extractItems } from './client'
import type {
  AchievementDto,
  AuthResponse,
  CoinTransactionDto,
  CourseDto,
  CreateLectureRequest,
  LectureDto,
  LectureQuery,
  LocationDto,
  PagedResult,
  ReviewDto,
  ReviewQuery,
  ReviewPromptDto,
  SyncResultDto,
  SyncScheduleRequest,
  SyncStatusDto,
  TagDto,
  UpdateReviewPromptRequest,
  UserAchievementDto,
  AdminDashboardStatsDto,
  CalendarSubscriptionDto,
  CurrentUserDto,
  UserDto,
  UserQuery,
  UserNotificationDto,
  UserStatsDto,
} from './types'

export const authApi = {
  loginMicrosoft: (authorizationCode: string, redirectUri?: string) =>
    apiRequest<AuthResponse>('/auth/login/microsoft', {
      method: 'POST',
      body: JSON.stringify({ authorizationCode, redirectUri }),
    }),
  refresh: () => apiRequest<AuthResponse>('/auth/refresh', { method: 'POST' }),
  logout: () => apiRequest<void>('/auth/logout', { method: 'POST' }),
  me: () => apiRequest<CurrentUserDto>('/auth/me'),
}

export const lecturesApi = {
  async list(query: LectureQuery = {}) {
    const payload = await apiRequest<PagedResult<LectureDto> | LectureDto[]>('/lectures', {
      query: query as Record<string, unknown>,
    })
    return extractItems(payload)
  },
  get: (id: string | number) => apiRequest<LectureDto>(`/lectures/${id}`),
  create: (payload: CreateLectureRequest) =>
    apiRequest<LectureDto>('/lectures', {
      method: 'POST',
      body: JSON.stringify(payload),
    }),
  enroll: (id: string | number) => apiRequest<void>(`/lectures/${id}/enroll`, { method: 'POST' }),
  unenroll: (id: string | number) =>
    apiRequest<void>(`/lectures/${id}/enroll`, { method: 'DELETE' }),
  async reviews(id: string | number) {
    const payload = await apiRequest<PagedResult<ReviewDto> | ReviewDto[]>(
      `/lectures/${id}/reviews`,
    )
    return extractItems(payload)
  },
}

export const usersApi = {
  me: () => apiRequest<CurrentUserDto>('/users/me'),
  updateMe: (payload: { displayName?: string | null; avatarUrl?: string | null }) =>
    apiRequest<CurrentUserDto>('/users/me', {
      method: 'PUT',
      body: JSON.stringify(payload),
    }),
  myStats: () => apiRequest<UserStatsDto>('/users/me/stats'),
  adminStats: () => apiRequest<AdminDashboardStatsDto>('/users/admin/stats'),
  async myEnrollments() {
    const payload = await apiRequest<PagedResult<LectureDto> | LectureDto[] | undefined>(
      '/users/me/enrollments',
    )
    return extractItems(payload)
  },
  downloadMyEnrollmentsIcs: () => apiRequestBlob('/users/me/enrollments.ics'),
  downloadEnrollmentIcs: (lectureId: string | number) =>
    apiRequestBlob(`/users/me/enrollments/${lectureId}.ics`),
  getCalendarSubscription: () =>
    apiRequest<CalendarSubscriptionDto>('/users/me/enrollments/calendar-subscription'),
  async myAchievements() {
    const payload = await apiRequest<
      PagedResult<UserAchievementDto> | UserAchievementDto[] | AchievementDto[]
    >('/users/me/achievements')
    if (Array.isArray(payload)) return payload
    return payload.items ?? []
  },
  async myTransactions() {
    const payload = await apiRequest<PagedResult<CoinTransactionDto> | CoinTransactionDto[]>(
      '/users/me/transactions',
    )
    return extractItems(payload)
  },
  get: (id: string | number) => apiRequest<UserDto>(`/users/${id}`),
  async list(query: UserQuery = {}) {
    const payload = await apiRequest<PagedResult<UserDto> | UserDto[]>('/users', {
      query: query as Record<string, unknown>,
    })
    return extractItems(payload)
  },
  stats: (id: string | number) => apiRequest<UserStatsDto>(`/users/${id}/stats`),
  async enrollments(id: string | number) {
    const payload = await apiRequest<PagedResult<LectureDto> | LectureDto[] | undefined>(
      `/users/${id}/enrollments`,
    )
    return extractItems(payload)
  },
  async achievements(id: string | number) {
    const payload = await apiRequest<
      PagedResult<UserAchievementDto> | UserAchievementDto[] | AchievementDto[]
    >(`/users/${id}/achievements`)
    if (Array.isArray(payload)) return payload
    return payload.items ?? []
  },
  async transactions(id: string | number) {
    const payload = await apiRequest<PagedResult<CoinTransactionDto> | CoinTransactionDto[]>(
      `/users/${id}/transactions`,
    )
    return extractItems(payload)
  },
  setRole: (id: string | number, roles: Array<'Student' | 'Teacher' | 'Admin'>) =>
    apiRequest<void>(`/users/${id}/role`, {
      method: 'PATCH',
      body: JSON.stringify(roles),
    }),
  setActive: (id: string | number, isActive: boolean) =>
    apiRequest<void>(`/users/${id}/active`, {
      method: 'PATCH',
      body: JSON.stringify(isActive),
    }),
}

export const achievementsApi = {
  async list() {
    const payload = await apiRequest<PagedResult<AchievementDto> | AchievementDto[]>(
      '/achievements',
    )
    return extractItems(payload)
  },
}

export const notificationsApi = {
  async list() {
    const payload = await apiRequest<PagedResult<UserNotificationDto> | UserNotificationDto[]>(
      '/notifications',
    )
    return extractItems(payload)
  },
  markAllRead: () => apiRequest<void>('/notifications/read-all', { method: 'PATCH' }),
}

function normalizePagedResult<T>(
  payload: PagedResult<T> | T[] | undefined,
  query: { Page?: number; PageSize?: number } = {},
): PagedResult<T> {
  if (!Array.isArray(payload) && payload) return payload

  const items = payload ?? []
  const page = query.Page ?? 1
  const pageSize = query.PageSize ?? items.length
  const totalPages = pageSize > 0 ? Math.ceil(items.length / pageSize) : 0

  return {
    items,
    totalCount: items.length,
    page,
    pageSize,
    totalPages,
  }
}

async function listReviewsPage(query: ReviewQuery = {}) {
  const payload = await apiRequest<PagedResult<ReviewDto> | ReviewDto[]>('/reviews', {
    query: query as Record<string, unknown>,
  })
  return normalizePagedResult(payload, query)
}

export const reviewsApi = {
  create: (lectureId: string | number, rating: 'Like' | 'Neutral' | 'Dislike', text: string) =>
    apiRequest<ReviewDto>('/reviews', {
      method: 'POST',
      body: JSON.stringify({ lectureId: Number(lectureId), rating, text }),
    }),
  getPrompt: () => apiRequest<ReviewPromptDto>('/reviews/llm-prompt'),
  updatePrompt: (payload: UpdateReviewPromptRequest) =>
    apiRequest<ReviewPromptDto>('/reviews/llm-prompt', {
      method: 'PUT',
      body: JSON.stringify(payload),
    }),
  listPage: listReviewsPage,
  async list(query: ReviewQuery = { PageSize: 100 }) {
    return (await listReviewsPage(query)).items
  },
  reanalyze: (id: string | number) =>
    apiRequest<void>(`/reviews/${id}/reanalyze`, { method: 'POST' }),
}

export const coursesApi = {
  async list() {
    const payload = await apiRequest<PagedResult<CourseDto> | CourseDto[]>('/courses', {
      query: { PageSize: 100 },
    })
    return extractItems(payload)
  },
}

export const locationsApi = {
  async list() {
    const payload = await apiRequest<PagedResult<LocationDto> | LocationDto[]>('/locations')
    return extractItems(payload)
  },
}

export const tagsApi = {
  async list() {
    const payload = await apiRequest<PagedResult<TagDto> | TagDto[]>('/tags')
    return extractItems(payload)
  },
}

export const syncApi = {
  status: () => apiRequest<SyncStatusDto>('/sync/status'),
  schedule: (request: SyncScheduleRequest) =>
    apiRequest<SyncResultDto>('/sync/schedule', {
      method: 'POST',
      body: JSON.stringify(request),
    }),
  rooms: () => apiRequest<SyncResultDto>('/sync/rooms', { method: 'POST' }),
}
