# teacher-bff GraphQL Schema (SDL-first, president §2.17)
# 版本：v1（P2 第一版，coord 仲裁）
# 负责人：ai03
# 关联：contracts/teacher-bff_contract.md §1.3、workline §3.1
#
# 设计原则（02-architecture-design.md §5.1）：
#   1. 按教学场景域组织（不按角色分），教导主任/教研组长复用同一 schema
#   2. Query 为主，Mutation 谨慎（BFF 偏读多写少）
#   3. N+1 防御：所有 list 字段经 DataLoader（P4 全量接入）
#   4. 复杂度限制：depth ≤ 7，query cost ≤ 1000
#   5. admin 命名空间预留（president §5.1：P2 预留 schema，P6 实现 Resolver）
#
# 错误响应格式：GraphQL errors 数组 + extensions.code = BFF_TEACHER_* + extensions.traceId
# 降级模式 B（president §2.6）：success=true + error=null + data 内 degraded 字段
#
# 阶段标注：
#   P2 = 当前实现（iam gRPC，未启用字段返 null + extensions.warning = "field_unavailable_in_p2"）
#   P3+ = 跨阶段扩展例外（president §2.3），Resolver 内逐步补 gRPC 调用

scalar DateTime

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

type User {
  id: ID!
  email: String!
  name: String!
  roles: [String!]!
  permissions: [String!]!
  dataScope: DataScope!
}

enum DataScope {
  SELF
  CLASS
  GRADE
  SCHOOL
  DISTRICT
  ALL
}

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

type Class {
  id: ID!
  name: String!
  gradeId: String!
  # 延迟加载：班级下的考试（P3+ core-edu gRPC）
  exams: [Exam!]!
  # 延迟加载：班级下的作业（P3+ core-edu gRPC）
  homework: [Homework!]!
}

type Exam {
  id: ID!
  title: String!
  classId: ID!
  status: ExamStatus!
  publishedAt: DateTime
  # 延迟加载：考试下的成绩（P3+ core-edu gRPC）
  grades: [Grade!]!
}

enum ExamStatus {
  DRAFT
  PUBLISHED
  IN_PROGRESS
  GRADING
  SCORED
  ARCHIVED
}

type Homework {
  id: ID!
  title: String!
  classId: ID!
  dueDate: DateTime!
  submissions: [Submission!]!
}

type Submission {
  id: ID!
  studentId: ID!
  submittedAt: DateTime!
  status: SubmissionStatus!
}

enum SubmissionStatus {
  NOT_SUBMITTED
  SUBMITTED
  GRADED
}

type Grade {
  id: ID!
  examId: ID!
  studentId: ID!
  score: Float!
  rank: Int
  submittedAt: DateTime!
}

type DashboardStats {
  totalExams: Int
  pendingGrading: Int
  todayHomework: Int
}

# Dashboard 聚合数据（P2: iam gRPC 用户基础信息，stats/classes 为 null + warning）
type DashboardData {
  user: User
  classes: [Class!]!
  viewports: [ViewportItem!]!
  stats: DashboardStats
}

# ============ Query ============
# P2 核心 5 Query（workline §3.2）：dashboard / viewports / me / classes / class

type Query {
  # 仪表盘聚合（P2: iam gRPC；P3+: + core-edu + data-ana）
  # @dataScope: OWN
  dashboard: DashboardData!

  # 视口配置（L1 导航，iam.GetViewports）
  viewports: [ViewportItem!]!

  # 当前用户信息（iam.GetUserInfo + GetEffectivePermissions）
  me: User!

  # 教师班级列表（P2: iam 数据；P3+: core-edu.GetClassesByTeacher）
  # @dataScope: OWN
  classes: [Class!]!

  # 单个班级详情（P3+: core-edu）
  # @permission: CLASS_READ
  # @dataScope: OWN
  class(id: ID!): Class

  # ===== P3+ 跨阶段扩展（core-edu gRPC，按 §2.3 跨阶段扩展例外新增）=====

  # 班级下的考试列表（P3: core-edu.ExamService.ListExamsByClass）
  # @permission: EXAM_READ
  # @dataScope: OWN
  exams(classId: ID!): [Exam!]!

  # 班级下的作业列表（P3: core-edu.HomeworkService.ListHomeworkByClass）
  # @permission: HOMEWORK_READ
  # @dataScope: OWN
  homework(classId: ID!): [Homework!]!

  # 考试下的成绩列表（P3: core-edu.GradeService.ListGradesByExam）
  # @permission: GRADE_READ
  # @dataScope: OWN
  grades(examId: ID!): [Grade!]!

  # ===== P4+ 跨阶段扩展（content + data-ana gRPC）=====

  # 知识图谱学习路径（P4: content.KnowledgeGraphService.GetLearningPath）
  knowledgePath(knowledgePointId: ID!): KnowledgePath!

  # 班级成绩分析（P4: data-ana.AnalyticsService.GetClassPerformance）
  # @permission: ANALYTICS_TEACHER_DASHBOARD
  classPerformance(classId: ID!): ClassPerformance!

  # 学生薄弱点（P4: data-ana.AnalyticsService.GetStudentWeakness）
  studentWeakness(studentId: ID!): StudentWeakness!

  # 学习趋势（P4: data-ana.AnalyticsService.GetLearningTrend）
  learningTrend(studentId: ID!, dateRange: DateRangeInput): LearningTrend!

  # ===== P5+ 跨阶段扩展（ai + msg gRPC）=====

  # 教师通知列表（P5: msg.NotificationService.ListNotifications）
  notifications(unreadOnly: Boolean): [Notification!]!

  # ===== admin 命名空间（president §5.1：P2 预留 schema，P6 实现 Resolver）=====
  # admin-portal 复用 teacher-bff GraphQL endpoint，admin 操作低 QPS 无需独立 BFF
  admin: AdminQuery!
}

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

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

type Mutation {
  # ===== P3+ 跨阶段扩展（core-edu gRPC 透传）=====

  # 创建考试（P3: core-edu.ExamService.CreateExam）
  # @permission: EXAM_CREATE
  createExam(input: CreateExamInput!): Exam!

  # 布置作业（P3: core-edu.HomeworkService.AssignHomework）
  # @permission: HOMEWORK_ASSIGN
  assignHomework(input: AssignHomeworkInput!): Homework!

  # 录入成绩（P3: core-edu.GradeService.RecordGrade）
  # @permission: GRADE_RECORD
  recordGrade(input: RecordGradeInput!): Grade!

  # ===== P5+ 跨阶段扩展（ai + msg gRPC）=====

  # AI 出题（P5: ai.AiService.GenerateQuestion）
  generateQuestion(input: GenerateQuestionInput!): GeneratedQuestion!

  # 标记通知已读（P5: msg.NotificationService.MarkAsRead）
  markNotificationAsRead(id: ID!): Notification!

  # ===== admin 命名空间 Mutation（president §5.1：P2 预留，P6 实现）=====
  admin: AdminMutation!
}

input CreateExamInput {
  classId: ID!
  title: String!
  subject: String!
  scheduledAt: DateTime!
}

input AssignHomeworkInput {
  classId: ID!
  title: String!
  dueDate: DateTime!
}

input RecordGradeInput {
  examId: ID!
  studentId: ID!
  score: Float!
}

input GenerateQuestionInput {
  subject: String!
  gradeLevel: String!
  difficulty: String!
  knowledgePointIds: [ID!]!
}

# ============ P4+ 类型（content + data-ana）============

type KnowledgePath {
  knowledgePointId: ID!
  name: String!
  prerequisites: [KnowledgePoint!]!
}

type KnowledgePoint {
  id: ID!
  name: String!
  subject: String!
}

type ClassPerformance {
  classId: ID!
  averageScore: Float!
  passRate: Float!
  weaknessTopics: [String!]!
}

type StudentWeakness {
  studentId: ID!
  weakTopics: [String!]!
  recommendedExercises: [String!]!
}

type LearningTrend {
  studentId: ID!
  trend: [TrendPoint!]!
}

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

# ============ P5+ 类型（ai + msg）============

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

enum NotificationType {
  SYSTEM
  EXAM
  HOMEWORK
  GRADE
  ATTENDANCE
}

type GeneratedQuestion {
  id: ID!
  subject: String!
  difficulty: String!
  content: String!
  answer: String!
}

# ============ admin 命名空间（president §5.1：P2 预留 schema，P6 实现 Resolver）============
# P2: 类型声明占位，Resolver 返 null（不阻塞 admin-portal schema 内省）
# P6: ai03 实现 admin Resolver 真实数据（用户/角色/学校/组织/审计日志管理）

type AdminQuery {
  # 用户管理
  users(page: Int = 1, pageSize: Int = 20): AdminUserPage
  user(id: ID!): AdminUser

  # 角色权限管理
  roles: [AdminRole!]!
  role(id: ID!): AdminRole

  # 学校设置
  school: AdminSchool

  # 组织管理
  organizations: [AdminOrganization!]!

  # 审计日志查询
  auditLogs(page: Int = 1, pageSize: Int = 20): AuditLogPage
}

type AdminMutation {
  createUser(input: AdminCreateUserInput!): AdminUser!
  updateUser(id: ID!, input: AdminUpdateUserInput!): AdminUser!
  deleteUser(id: ID!): Boolean!

  createRole(input: AdminCreateRoleInput!): AdminRole!
  updateRole(id: ID!, input: AdminUpdateRoleInput!): AdminRole!
  deleteRole(id: ID!): Boolean!

  updateSchool(input: AdminUpdateSchoolInput!): AdminSchool!

  createOrganization(input: AdminCreateOrganizationInput!): AdminOrganization!
  updateOrganization(id: ID!, input: AdminUpdateOrganizationInput!): AdminOrganization!
  deleteOrganization(id: ID!): Boolean!
}

type AdminUser {
  id: ID!
  email: String!
  name: String!
  roles: [String!]!
  status: String!
  createdAt: DateTime!
  lastLoginAt: DateTime
}

type AdminUserPage {
  edges: [AdminUser!]!
  totalCount: Int!
  page: Int!
  pageSize: Int!
}

type AdminRole {
  id: ID!
  name: String!
  description: String
  permissions: [String!]!
  userCount: Int!
}

type AdminSchool {
  id: ID!
  name: String!
  address: String
  phone: String
  studentCount: Int!
  teacherCount: Int!
  classCount: Int!
}

type AdminOrganization {
  id: ID!
  name: String!
  type: String!
  parentId: ID
  createdAt: DateTime!
}

type AuditLogPage {
  edges: [AuditLog!]!
  totalCount: Int!
  page: Int!
  pageSize: Int!
}

type AuditLog {
  id: ID!
  actorUserId: ID!
  action: String!
  resourceType: String!
  resourceId: ID
  occurredAt: DateTime!
  ip: String
}

input AdminCreateUserInput {
  email: String!
  name: String!
  roleIds: [ID!]!
}

input AdminUpdateUserInput {
  name: String
  roleIds: [ID!]
  status: String
}

input AdminCreateRoleInput {
  name: String!
  description: String
  permissions: [String!]!
}

input AdminUpdateRoleInput {
  name: String
  description: String
  permissions: [String!]
}

input AdminUpdateSchoolInput {
  name: String
  address: String
  phone: String
}

input AdminCreateOrganizationInput {
  name: String!
  type: String!
  parentId: ID
}

input AdminUpdateOrganizationInput {
  name: String
  type: String
  parentId: ID
}
