/**
 * M3 审核工作台 - 数据访问层
 *
 * 处理课案状态迁移、审核记录、审核队列查询。
 */
import "server-only";
import { db } from "@/shared/db";
import { lessonPlans, lessonPlanReviewRecords } from "@/shared/db/schema";
import { and, eq, desc, asc, inArray } from "drizzle-orm";
import type { LessonPlanStatus } from "./types";
import { LESSON_PLAN_STATUS_TRANSITIONS, isReviewableStatus } from "./types";

/** 审核记录 */
export interface LessonPlanReviewRecord {
  id: string;
  planId: string;
  reviewerId: string;
  decision: "approved" | "rejected";
  comment?: string;
  previousStatus: LessonPlanStatus;
  newStatus: LessonPlanStatus;
  createdAt: Date;
}

/**
 * 校验状态迁移合法性
 */
export function isValidTransition(
  from: LessonPlanStatus,
  to: LessonPlanStatus,
): boolean {
  return LESSON_PLAN_STATUS_TRANSITIONS[from]?.includes(to) ?? false;
}

/**
 * 提交课案审核（draft/rejected → submitted）
 */
export async function submitForReview(
  planId: string,
  _userId: string,
): Promise<LessonPlanStatus> {
  const plan = await db
    .select({ status: lessonPlans.status })
    .from(lessonPlans)
    .where(eq(lessonPlans.id, planId))
    .limit(1);

  if (plan.length === 0) {
    throw new Error("PLAN_NOT_FOUND");
  }
  const currentStatus = plan[0]!.status as LessonPlanStatus;
  if (!isReviewableStatus(currentStatus) && currentStatus !== "draft" && currentStatus !== "rejected") {
    throw new Error("INVALID_STATUS_TRANSITION");
  }

  await db
    .update(lessonPlans)
    .set({ status: "submitted", updatedAt: new Date() })
    .where(eq(lessonPlans.id, planId));

  return "submitted";
}

/**
 * 审核课案（submitted → approved/rejected）
 * 同时写入审核记录
 */
export async function reviewPlan(
  planId: string,
  reviewerId: string,
  decision: "approved" | "rejected",
  comment?: string,
): Promise<{ newStatus: LessonPlanStatus; record: LessonPlanReviewRecord }> {
  const plan = await db
    .select({ status: lessonPlans.status })
    .from(lessonPlans)
    .where(eq(lessonPlans.id, planId))
    .limit(1);

  if (plan.length === 0) {
    throw new Error("PLAN_NOT_FOUND");
  }
  const previousStatus = plan[0]!.status as LessonPlanStatus;
  if (!isReviewableStatus(previousStatus)) {
    throw new Error("PLAN_NOT_REVIEWABLE");
  }

  const newStatus: LessonPlanStatus = decision === "approved" ? "approved" : "rejected";
  if (!isValidTransition(previousStatus, newStatus)) {
    throw new Error("INVALID_STATUS_TRANSITION");
  }

  // 事务：更新状态 + 写入审核记录
  await db.transaction(async (tx) => {
    await tx
      .update(lessonPlans)
      .set({ status: newStatus, updatedAt: new Date() })
      .where(eq(lessonPlans.id, planId));

    await tx.insert(lessonPlanReviewRecords).values({
      planId,
      reviewerId,
      decision,
      comment: comment ?? null,
      previousStatus,
      newStatus,
    });
  });

  const record: LessonPlanReviewRecord = {
    id: "",
    planId,
    reviewerId,
    decision,
    comment,
    previousStatus,
    newStatus,
    createdAt: new Date(),
  };
  return { newStatus, record };
}

/**
 * 查询课案的所有审核记录
 */
export async function getReviewRecordsByPlanId(
  planId: string,
): Promise<LessonPlanReviewRecord[]> {
  const rows = await db
    .select()
    .from(lessonPlanReviewRecords)
    .where(eq(lessonPlanReviewRecords.planId, planId))
    .orderBy(desc(lessonPlanReviewRecords.createdAt));

  return rows.map((r) => ({
    id: r.id,
    planId: r.planId,
    reviewerId: r.reviewerId,
    decision: r.decision as "approved" | "rejected",
    comment: r.comment ?? undefined,
    previousStatus: r.previousStatus as LessonPlanStatus,
    newStatus: r.newStatus as LessonPlanStatus,
    createdAt: r.createdAt,
  }));
}

/**
 * 查询待审核队列（教研组长用）
 */
export async function getPendingReviewPlans(
  reviewerGradeIds?: string[],
  reviewerSubjectIds?: string[],
): Promise<
  Array<{
    id: string;
    title: string;
    status: LessonPlanStatus;
    creatorId: string;
    gradeId: string | null;
    subjectId: string | null;
    submittedAt: Date;
  }>
> {
  const conditions = [eq(lessonPlans.status, "submitted")];

  const rows = await db
    .select({
      id: lessonPlans.id,
      title: lessonPlans.title,
      status: lessonPlans.status,
      creatorId: lessonPlans.creatorId,
      gradeId: lessonPlans.gradeId,
      subjectId: lessonPlans.subjectId,
      submittedAt: lessonPlans.updatedAt,
    })
    .from(lessonPlans)
    .where(and(...conditions))
    .orderBy(asc(lessonPlans.updatedAt));

  // 按教研组长权限过滤（gradeId/subjectId）
  return rows
    .filter((r) => {
      if (reviewerGradeIds && reviewerGradeIds.length > 0 && !reviewerGradeIds.includes(r.gradeId ?? "")) {
        return false;
      }
      if (reviewerSubjectIds && reviewerSubjectIds.length > 0 && !reviewerSubjectIds.includes(r.subjectId ?? "")) {
        return false;
      }
      return true;
    })
    .map((r) => ({
      id: r.id,
      title: r.title,
      status: r.status as LessonPlanStatus,
      creatorId: r.creatorId,
      gradeId: r.gradeId,
      subjectId: r.subjectId,
      submittedAt: r.submittedAt,
    }));
}

/**
 * 撤回审核（教师主动撤回：submitted → draft）
 */
export async function withdrawSubmission(
  planId: string,
): Promise<LessonPlanStatus> {
  const plan = await db
    .select({ status: lessonPlans.status })
    .from(lessonPlans)
    .where(eq(lessonPlans.id, planId))
    .limit(1);

  if (plan.length === 0) {
    throw new Error("PLAN_NOT_FOUND");
  }
  const currentStatus = plan[0]!.status as LessonPlanStatus;
  if (!isValidTransition(currentStatus, "draft")) {
    throw new Error("INVALID_STATUS_TRANSITION");
  }

  await db
    .update(lessonPlans)
    .set({ status: "draft", updatedAt: new Date() })
    .where(eq(lessonPlans.id, planId));

  return "draft";
}

/**
 * 按状态批量查询课案（审核仪表盘用途。
 */
export async function getPlansByStatuses(
  statuses: LessonPlanStatus[],
  creatorId?: string,
): Promise<
  Array<{
    id: string;
    title: string;
    status: LessonPlanStatus;
    creatorId: string;
    updatedAt: Date;
  }>
> {
  const conditions = [];
  if (statuses.length > 0) {
    conditions.push(inArray(lessonPlans.status, statuses));
  }
  if (creatorId) {
    conditions.push(eq(lessonPlans.creatorId, creatorId));
  }

  const rows = await db
    .select({
      id: lessonPlans.id,
      title: lessonPlans.title,
      status: lessonPlans.status,
      creatorId: lessonPlans.creatorId,
      updatedAt: lessonPlans.updatedAt,
    })
    .from(lessonPlans)
    .where(conditions.length > 0 ? and(...conditions) : undefined)
    .orderBy(desc(lessonPlans.updatedAt));

  return rows.map((r) => ({
    id: r.id,
    title: r.title,
    status: r.status as LessonPlanStatus,
    creatorId: r.creatorId,
    updatedAt: r.updatedAt,
  }));
}
