# parent-bff GraphQL Schema（SDL 契约，对齐 02-architecture-design.md §4.2）
#
# 本文件是 parent-bff GraphQL 端点的契约唯一源（single source of truth）。
# - 前端 parent-portal 引用本文件生成 TypeScript 类型
# - 后端 parent-bff 引用本文件加载为 GraphQLSchema
# - CI 强制检测 breaking change（与 main 分支对比）
#
# 仲裁依据：
# - U3：GraphQL P2 立即引入（parent-bff P4 直接用 GraphQL，不走 REST 过渡）
# - C1：错误码前缀 BFF_PARENT_
# - U4：BFF 豁免 @RequirePermission，仅校验 x-user-id + ChildGuard
# - 02 §9 #5：depth ≤ 7 / cost ≤ 1000

scalar DateTime

# ============ Types ============

type Parent {
  id: ID!
  email: String!
  name: String!
  avatar: String
  roles: [String!]!
  dataScope: DataScope!
}

enum DataScope {
  SELF
  CHILDREN
  CLASS
  GRADE
  SCHOOL
  DISTRICT
  ALL
}

type ViewportItem {
  key: String!
  label: String!
  route: String!
  icon: String
  sortOrder: String!
  requiredPermission: String
}

type Child {
  id: ID!
  name: String!
  grade: String!
  class: ClassInfo!
  lastGrade: Grade
  grades(page: Int = 1, pageSize: Int = 20, subject: String): GradePage!
  homework: [Homework!]!
  exams: [Exam!]!
  analytics: ChildAnalytics!
}

type ClassInfo {
  id: ID!
  name: String!
  gradeId: String!
}

type Grade {
  id: ID!
  examId: ID!
  examTitle: String!
  subject: String!
  score: Float!
  rank: Int
  gradedAt: DateTime!
}

type GradePage {
  items: [Grade!]!
  pagination: Pagination!
}

type Pagination {
  page: Int!
  pageSize: Int!
  total: Int!
}

type Homework {
  id: ID!
  title: String!
  classId: ID!
  dueDate: DateTime!
  status: HomeworkStatus!
  submittedAt: DateTime
}

enum HomeworkStatus {
  NOT_SUBMITTED
  SUBMITTED
  GRADED
  OVERDUE
}

type Exam {
  id: ID!
  title: String!
  classId: ID!
  status: ExamStatus!
  examDate: DateTime!
  publishedAt: DateTime
}

enum ExamStatus {
  DRAFT
  PUBLISHED
  IN_PROGRESS
  GRADING
  SCORED
  ARCHIVED
}

type ChildAnalytics {
  childId: ID!
  weakness: [WeaknessTopic!]!
  trend: [TrendPoint!]!
  classRank: Int
  classAverage: Float
}

type WeaknessTopic {
  knowledgePointId: ID!
  name: String!
  subject: String!
  masteryRate: Float!
}

type TrendPoint {
  date: DateTime!
  score: Float!
  subject: String
}

type Notification {
  id: ID!
  type: NotificationType!
  title: String!
  content: String!
  read: Boolean!
  childId: ID
  createdAt: DateTime!
}

enum NotificationType {
  SYSTEM
  EXAM
  HOMEWORK
  GRADE
  ATTENDANCE
  ANNOUNCEMENT
}

type NotificationPreferences {
  channels: [NotificationChannel!]!
  eventTypes: NotificationEventTypes!
}

enum NotificationChannel {
  APP
  SMS
  EMAIL
  WECHAT
}

type NotificationEventTypes {
  gradeReleased: Boolean!
  homeworkGraded: Boolean!
  examPublished: Boolean!
  attendanceAlert: Boolean!
  schoolAnnouncement: Boolean!
}

type DashboardData {
  parent: Parent
  children: [Child!]!
  viewports: [ViewportItem!]!
  unreadNotifications: Int!
  degraded: Boolean!
}

# ============ Query ============

type Query {
  dashboard: DashboardData!
  viewports: [ViewportItem!]!
  me: Parent!
  children: [Child!]!
  child(childId: ID!): Child
  childGrades(
    childId: ID!
    page: Int = 1
    pageSize: Int = 20
    subject: String
  ): GradePage!
  childHomework(childId: ID!): [Homework!]!
  childExams(childId: ID!): [Exam!]!
  childAnalytics(childId: ID!, dateRange: DateRangeInput): ChildAnalytics!
  notifications(
    unreadOnly: Boolean
    page: Int = 1
    pageSize: Int = 20
  ): [Notification!]!
  notificationPreferences: NotificationPreferences!
}

input DateRangeInput {
  start: DateTime!
  end: DateTime!
}

# ============ Mutation ============

type Mutation {
  selectChild(childId: ID!): SelectChildResult!
  markNotificationRead(notificationId: ID!): Notification!
  updateNotificationPreferences(
    input: UpdateNotificationPreferencesInput!
  ): NotificationPreferences!
}

type SelectChildResult {
  childId: ID!
  selectedAt: DateTime!
  audited: Boolean!
}

input UpdateNotificationPreferencesInput {
  channels: [NotificationChannel!]!
  eventTypes: NotificationEventTypesInput!
}

input NotificationEventTypesInput {
  gradeReleased: Boolean
  homeworkGraded: Boolean
  examPublished: Boolean
  attendanceAlert: Boolean
  schoolAnnouncement: Boolean
}
