import { eq, and } from "drizzle-orm"

import { db } from "@/shared/db"
import {
  users,
  usersToRoles,
  roles,
  parentStudentRelations,
} from "@/shared/db/schema"
import type { Role } from "@/shared/types/permissions"
import { resolvePrimaryRole } from "@/shared/lib/role-utils"
import type { OnboardingRoleInfo, OnboardingStatus, BindParentToChildParams } from "./types"

/**
 * 读取 onboarding 状态：是否需要引导 + 用户已有角色。
 *
 * 角色来源：usersToRoles（管理员预分配），onboarding 不写此表。
 */
export async function getOnboardingStatus(userId: string): Promise<OnboardingStatus> {
  const [userRow, roleRows] = await Promise.all([
    db.query.users.findFirst({
      where: eq(users.id, userId),
      columns: { onboardedAt: true, name: true },
    }),
    db
      .select({ name: roles.name })
      .from(usersToRoles)
      .innerJoin(roles, eq(usersToRoles.roleId, roles.id))
      .where(eq(usersToRoles.userId, userId)),
  ])

  const allRoles = roleRows
    .map((r) => r.name)
    .filter((r): r is Role => typeof r === "string")
  const primary = resolvePrimaryRole(allRoles)
  const roleInfo: OnboardingRoleInfo = { primary, all: allRoles }

  return {
    required: !userRow?.onboardedAt,
    roles: roleInfo,
    name: userRow?.name ?? "",
  }
}

/**
 * 更新用户基础资料（姓名/电话/住址）。
 * 不涉及角色与班级绑定，独立可复用。
 */
export async function updateUserProfile(
  userId: string,
  data: { name: string; phone: string; address?: string }
): Promise<void> {
  await db
    .update(users)
    .set({
      name: data.name,
      phone: data.phone.length ? data.phone : null,
      address: data.address && data.address.length ? data.address : null,
    })
    .where(eq(users.id, userId))
}

/**
 * 家长绑定子女：三因子验证（v3 P0-2 修复，对标 PowerSchool Access ID + Access Password）。
 *
 * 安全设计：
 * - 验证因子 1：子女邮箱（已知信息）
 * - 验证因子 2：子女生日（YYYY-MM-DD，365 种可能）
 * - 验证因子 3：子女手机号后 4 位（10000 种可能，v3 新增）
 * 组合空间：365 × 10000 = 3.65M 种，显著降低枚举攻击风险。
 *
 * 与 PowerSchool 的差距：PowerSchool 用学校发放的 Access ID + Access Password（强凭证），
 * 本系统暂复用子女已有信息作为验证因子，后续可引入独立绑定码表进一步提升安全性。
 *
 * 其他安全设计：
 * - 一个家长可绑定多个子女（parent_student_relations 表支持）。
 * - 防越权：仅当三因子全部匹配时才建立关系。
 * - 幂等：若已存在关系则不重复插入。
 */
export async function bindParentToChild(
  params: BindParentToChildParams
): Promise<{ studentId: string } | { error: string }> {
  const { parentId, childEmail, childBirthDate, childPhoneSuffix, relation } = params

  const child = await db.query.users.findFirst({
    where: eq(users.email, childEmail.trim().toLowerCase()),
    columns: { id: true, birthDate: true, phone: true },
  })

  if (!child) return { error: "未找到该邮箱对应的学生" }
  if (!child.birthDate) return { error: "学生未设置出生日期，请联系管理员" }
  if (!child.phone) return { error: "学生未设置手机号，请联系管理员" }

  // 验证因子 2：子女生日
  const childBirthStr = child.birthDate.toISOString().slice(0, 10)
  if (childBirthStr !== childBirthDate) {
    return { error: "子女生日不匹配" }
  }

  // 验证因子 3：子女手机号后 4 位（v3 新增）
  const childPhoneLast4 = child.phone.replace(/\D/g, "").slice(-4)
  if (childPhoneLast4 !== childPhoneSuffix) {
    return { error: "子女手机号后 4 位不匹配" }
  }

  // 幂等：若已存在关系则不重复插入
  const existing = await db
    .select({ id: parentStudentRelations.id })
    .from(parentStudentRelations)
    .where(
      and(
        eq(parentStudentRelations.parentId, parentId),
        eq(parentStudentRelations.studentId, child.id)
      )
    )
    .limit(1)

  if (existing.length === 0) {
    await db.insert(parentStudentRelations).values({
      parentId,
      studentId: child.id,
      relation: relation && relation.length ? relation : null,
    })
  }

  return { studentId: child.id }
}
