"use server";

import { requirePermission } from "@/shared/lib/auth-guard";
import { Permissions } from "@/shared/types/permissions";
import type { ActionState } from "@/shared/types/action-state";
import { revalidatePath } from "next/cache";
import { getTranslations } from "next-intl/server";
import { getCurrentStudentUser } from "@/modules/users/data-access";
import { getGradeNameById } from "@/modules/school/data-access";
import {
    createTextbook,
    createChapter,
    updateChapterContent,
    deleteChapter,
    createKnowledgePoint,
    deleteKnowledgePoint,
    updateKnowledgePoint,
    updateTextbook,
    deleteTextbook,
    reorderChapters,
    verifyChapterBelongsToTextbook,
    verifyKnowledgePointBelongsToTextbook,
    getKnowledgePointsByChapterId,
    getTextbookById,
    createPrerequisite,
    deletePrerequisite,
    getPrerequisiteEdgesForTextbook,
} from "./data-access";
import {
    getKnowledgePointsWithRelations,
    getStudentKpMastery,
    getClassKpMastery,
} from "./data-access-graph";
import { getClassStudents } from "@/modules/classes/data-access-students";
import {
    CreateTextbookSchema,
    UpdateTextbookSchema,
    CreateChapterSchema,
    UpdateChapterContentSchema,
    CreateKnowledgePointSchema,
    UpdateKnowledgePointSchema,
    CreatePrerequisiteSchema,
    DeletePrerequisiteSchema,
} from "./schema";
import { hasCycleAfterAddingEdge } from "./utils";
import type { GraphViewMode, KnowledgeGraphData, KnowledgePoint, MasteryInfo } from "./types";
import { handleActionError } from "@/shared/lib/action-utils";

const getStringValue = (formData: FormData, key: string): string => {
  const value = formData.get(key)
  return typeof value === "string" ? value : ""
}

export async function reorderChaptersAction(
    chapterId: string,
    newIndex: number,
    parentId: string | null,
    textbookId: string
): Promise<ActionState> {
    try {
        const t = await getTranslations("textbooks.action");
        await requirePermission(Permissions.TEXTBOOK_UPDATE);
        // P0-4 资源归属校验：防止越权操作其他教材的章节
        const belongs = await verifyChapterBelongsToTextbook(chapterId, textbookId)
        if (!belongs) {
            return { success: false, message: t("chapterNotBelong") };
        }
        await reorderChapters(chapterId, newIndex, parentId);
        revalidatePath(`/teacher/textbooks/${textbookId}`);
        return { success: true, message: t("chaptersReordered") };
    } catch (e) {
        return handleActionError(e)
    }
}

export async function createTextbookAction(
  prevState: ActionState | null,
  formData: FormData
): Promise<ActionState> {
  const t = await getTranslations("textbooks.action");
  const parsed = CreateTextbookSchema.safeParse({
    title: getStringValue(formData, "title"),
    subject: getStringValue(formData, "subject"),
    grade: getStringValue(formData, "grade"),
    publisher: getStringValue(formData, "publisher"),
  });

  if (!parsed.success) {
    return {
      success: false,
      message: t("fillRequired"),
      errors: parsed.error.flatten().fieldErrors,
    };
  }

  try {
    await requirePermission(Permissions.TEXTBOOK_CREATE);
    await createTextbook(parsed.data);
    revalidatePath("/teacher/textbooks");
    return {
      success: true,
      message: t("createSuccess"),
    };
  } catch (e) {
    return handleActionError(e)
  }
}

export async function updateTextbookAction(
  textbookId: string,
  prevState: ActionState | null,
  formData: FormData
): Promise<ActionState> {
  const t = await getTranslations("textbooks.action");
  const parsed = UpdateTextbookSchema.safeParse({
    id: textbookId,
    title: getStringValue(formData, "title"),
    subject: getStringValue(formData, "subject"),
    grade: getStringValue(formData, "grade"),
    publisher: getStringValue(formData, "publisher"),
  });

  if (!parsed.success) {
    return {
      success: false,
      message: t("fillRequired"),
      errors: parsed.error.flatten().fieldErrors,
    };
  }

  try {
    await requirePermission(Permissions.TEXTBOOK_UPDATE);
    await updateTextbook(parsed.data);
    revalidatePath(`/teacher/textbooks/${textbookId}`);
    return {
      success: true,
      message: t("updateSuccess"),
    };
  } catch (e) {
    return handleActionError(e)
  }
}

export async function deleteTextbookAction(
  textbookId: string
): Promise<ActionState> {
    try {
        const t = await getTranslations("textbooks.action");
        await requirePermission(Permissions.TEXTBOOK_DELETE);
        await deleteTextbook(textbookId);
        revalidatePath("/teacher/textbooks");
        return {
            success: true,
            message: t("deleteSuccess"),
        };
    } catch (e) {
        return handleActionError(e)
    }
}

export async function createChapterAction(
    textbookId: string,
    parentId: string | undefined,
    prevState: ActionState | null,
    formData: FormData
): Promise<ActionState> {
    const t = await getTranslations("textbooks.action");
    const parsed = CreateChapterSchema.safeParse({
        textbookId,
        title: getStringValue(formData, "title"),
        parentId,
        order: 0,
    });

    if (!parsed.success) {
        return {
            success: false,
            message: t("titleRequired"),
            errors: parsed.error.flatten().fieldErrors,
        };
    }

    try {
        await requirePermission(Permissions.TEXTBOOK_CREATE);
        await createChapter(parsed.data);
        revalidatePath(`/teacher/textbooks/${textbookId}`);
        return { success: true, message: t("chapterCreateSuccess") };
    } catch (e) {
        return handleActionError(e)
    }
}

export async function updateChapterContentAction(
    chapterId: string,
    content: string,
    textbookId: string
): Promise<ActionState> {
    const t = await getTranslations("textbooks.action");
    const parsed = UpdateChapterContentSchema.safeParse({
        chapterId,
        content,
    });

    if (!parsed.success) {
        return {
            success: false,
            message: t("invalidContent"),
            errors: parsed.error.flatten().fieldErrors,
        };
    }

    try {
        await requirePermission(Permissions.TEXTBOOK_UPDATE);
        // P0-4 资源归属校验
        const belongs = await verifyChapterBelongsToTextbook(chapterId, textbookId)
        if (!belongs) {
            return { success: false, message: t("chapterNotBelong") };
        }
        await updateChapterContent(parsed.data);
        revalidatePath(`/teacher/textbooks/${textbookId}`);
        return { success: true, message: t("contentUpdateSuccess") };
    } catch (e) {
        return handleActionError(e)
    }
}

export async function deleteChapterAction(
    chapterId: string,
    textbookId: string
): Promise<ActionState> {
    try {
        const t = await getTranslations("textbooks.action");
        await requirePermission(Permissions.TEXTBOOK_DELETE);
        // P0-4 资源归属校验
        const belongs = await verifyChapterBelongsToTextbook(chapterId, textbookId)
        if (!belongs) {
            return { success: false, message: t("chapterNotBelong") };
        }
        await deleteChapter(chapterId);
        revalidatePath(`/teacher/textbooks/${textbookId}`);
        return { success: true, message: t("chapterDeleteSuccess") };
    } catch (e) {
        return handleActionError(e)
    }
}

export async function createKnowledgePointAction(
    chapterId: string,
    textbookId: string,
    prevState: ActionState | null,
    formData: FormData
): Promise<ActionState> {
    const t = await getTranslations("textbooks.action");
    const parsed = CreateKnowledgePointSchema.safeParse({
        name: getStringValue(formData, "name"),
        description: getStringValue(formData, "description") || undefined,
        anchorText: getStringValue(formData, "anchorText") || undefined,
        chapterId,
    });

    if (!parsed.success) {
        return {
            success: false,
            message: t("nameRequired"),
            errors: parsed.error.flatten().fieldErrors,
        };
    }

    try {
        await requirePermission(Permissions.TEXTBOOK_CREATE);
        // P0-4 资源归属校验：确保 chapter 属于该 textbook，防止跨教材越权创建知识点
        const chapterBelongs = await verifyChapterBelongsToTextbook(chapterId, textbookId);
        if (!chapterBelongs) {
            return { success: false, message: t("chapterNotBelong") };
        }
        await createKnowledgePoint(parsed.data);
        revalidatePath(`/teacher/textbooks/${textbookId}`);
        return { success: true, message: t("kpCreateSuccess") };
    } catch (e) {
        return handleActionError(e)
    }
}

export async function deleteKnowledgePointAction(
    kpId: string,
    textbookId: string
): Promise<ActionState> {
    try {
        const t = await getTranslations("textbooks.action");
        await requirePermission(Permissions.TEXTBOOK_DELETE);
        // P0-4 资源归属校验
        const belongs = await verifyKnowledgePointBelongsToTextbook(kpId, textbookId)
        if (!belongs) {
            return { success: false, message: t("kpNotBelong") };
        }
        await deleteKnowledgePoint(kpId);
        revalidatePath(`/teacher/textbooks/${textbookId}`);
        return { success: true, message: t("kpDeleteSuccess") };
    } catch (e) {
        return handleActionError(e)
    }
}

export async function updateKnowledgePointAction(
    kpId: string,
    textbookId: string,
    prevState: ActionState | null,
    formData: FormData
): Promise<ActionState> {
    const t = await getTranslations("textbooks.action");
    const parsed = UpdateKnowledgePointSchema.safeParse({
        id: kpId,
        name: getStringValue(formData, "name"),
        description: getStringValue(formData, "description") || undefined,
        anchorText: getStringValue(formData, "anchorText") || undefined,
    });

    if (!parsed.success) {
        return {
            success: false,
            message: t("nameRequired"),
            errors: parsed.error.flatten().fieldErrors,
        };
    }

    try {
        await requirePermission(Permissions.TEXTBOOK_UPDATE);
        // P0-4 资源归属校验
        const belongs = await verifyKnowledgePointBelongsToTextbook(kpId, textbookId)
        if (!belongs) {
            return { success: false, message: t("kpNotBelong") };
        }
        await updateKnowledgePoint(parsed.data);
        revalidatePath(`/teacher/textbooks/${textbookId}`);
        return { success: true, message: t("kpUpdateSuccess") };
    } catch (e) {
        return handleActionError(e)
    }
}

/**
 * P2-3 知识点懒加载：按章节 ID 获取知识点。
 *
 * 用于详情页切换章节时按需加载，避免一次性拉取整本教材所有知识点。
 * 需 TEXTBOOK_READ 权限。
 */
export async function getKnowledgePointsByChapterAction(
    chapterId: string,
    textbookId: string
): Promise<ActionState<KnowledgePoint[]>> {
    try {
        const t = await getTranslations("textbooks.action");
        await requirePermission(Permissions.TEXTBOOK_READ);
        // P0-4 资源归属校验：确保 chapter 属于该 textbook
        const belongs = await verifyChapterBelongsToTextbook(chapterId, textbookId);
        if (!belongs) {
            return { success: false, message: t("chapterNotBelong") };
        }
        const knowledgePoints = await getKnowledgePointsByChapterId(chapterId);
        return { success: true, message: t("ok"), data: knowledgePoints };
    } catch (e) {
        return handleActionError(e)
    }
}

// ===== 知识图谱 Actions =====

/**
 * 获取知识图谱数据。
 *
 * - structure 模式：仅返回知识点+依赖+题目数
 * - student-mastery 模式：附加当前学生掌握度
 * - class-mastery 模式：附加班级平均掌握度（仅教师可用）
 *
 * P0 安全修复：学生端按年级 scope 过滤，防止跨年级越权查看教材图谱数据。
 * class-mastery 模式仅限教师使用（getClassStudents 已通过 getAccessibleClassIdsForTeacher 过滤）。
 */
export async function getKnowledgeGraphDataAction(
    textbookId: string,
    viewMode: GraphViewMode,
): Promise<ActionState<KnowledgeGraphData>> {
    try {
        const t = await getTranslations("textbooks.action");
        const ctx = await requirePermission(Permissions.TEXTBOOK_READ);

        // P0 数据范围校验：学生只能查看本年级教材的图谱
        if (ctx.dataScope.type === "class_members" || ctx.dataScope.type === "children") {
            const textbook = await getTextbookById(textbookId);
            if (!textbook) {
                return { success: false, message: t("notFound") };
            }
            // 学生/家长端：校验教材年级是否在允许范围内
            if (textbook.grade) {
                const allowedGradeIds = ctx.dataScope.gradeIds ?? [];
                if (allowedGradeIds.length > 0) {
                    const allowedGradeNames = await Promise.all(
                        allowedGradeIds.map((gid) => getGradeNameById(gid))
                    );
                    if (!allowedGradeNames.includes(textbook.grade)) {
                        return { success: false, message: t("notFound") };
                    }
                }
            }
        }

        const knowledgePointsData = await getKnowledgePointsWithRelations(textbookId);
        const masteryMap: Record<string, MasteryInfo> = {};

        if (viewMode === "student-mastery") {
            const student = await getCurrentStudentUser();
            if (student) {
                const mastery = await getStudentKpMastery(student.id, textbookId);
                for (const [kpId, info] of mastery) {
                    masteryMap[kpId] = info;
                }
            }
            // 无学生身份时 masteryMap 保持为空，前端将显示"未测评"状态
        } else if (viewMode === "class-mastery") {
            // class-mastery 模式仅限教师使用（dataScope.type === "class_taught"）
            // getClassStudents 内部已通过 getAccessibleClassIdsForTeacher 过滤，仅返回当前教师可访问班级的学生
            if (ctx.dataScope.type !== "class_taught" && ctx.dataScope.type !== "all") {
                return { success: false, message: t("noClassMasteryPermission") };
            }
            const students = await getClassStudents({ status: "active" });
            const studentIds = students.map((s) => s.id);
            if (studentIds.length > 0) {
                const mastery = await getClassKpMastery(studentIds, textbookId);
                for (const [kpId, info] of mastery) {
                    masteryMap[kpId] = info;
                }
            }
        }

        return {
            success: true,
            message: t("ok"),
            data: { knowledgePoints: knowledgePointsData, masteryMap, viewMode },
        };
    } catch (e) {
        return handleActionError(e)
    }
}

/**
 * 声明前置依赖（含循环检测）。
 */
export async function createPrerequisiteAction(
    formData: FormData,
): Promise<ActionState> {
    try {
        const t = await getTranslations("textbooks.action");
        await requirePermission(Permissions.TEXTBOOK_UPDATE);

        const knowledgePointId = getStringValue(formData, "knowledgePointId");
        const prerequisiteKpId = getStringValue(formData, "prerequisiteKpId");
        const textbookId = getStringValue(formData, "textbookId");

        const parsed = CreatePrerequisiteSchema.safeParse({
            knowledgePointId,
            prerequisiteKpId,
        });
        if (!parsed.success) {
            return { success: false, message: t("invalidInput") };
        }

        // 归属校验：两个知识点都必须属于当前教材，防止跨教材越权
        const kpBelongs = await verifyKnowledgePointBelongsToTextbook(
            parsed.data.knowledgePointId,
            textbookId,
        );
        if (!kpBelongs) {
            return { success: false, message: t("kpNotBelong") };
        }
        const prereqBelongs = await verifyKnowledgePointBelongsToTextbook(
            parsed.data.prerequisiteKpId,
            textbookId,
        );
        if (!prereqBelongs) {
            return { success: false, message: t("kpNotBelong") };
        }

        // 循环检测
        const existingEdges = await getPrerequisiteEdgesForTextbook(textbookId);
        if (hasCycleAfterAddingEdge(
            existingEdges,
            parsed.data.knowledgePointId,
            parsed.data.prerequisiteKpId,
        )) {
            return { success: false, message: t("cyclicDependency") };
        }

        await createPrerequisite(parsed.data);
        revalidatePath(`/teacher/textbooks/${textbookId}`);
        return { success: true, message: t("prerequisiteCreated") };
    } catch (e) {
        return handleActionError(e)
    }
}

/**
 * 删除前置依赖。
 */
export async function deletePrerequisiteAction(
    formData: FormData,
): Promise<ActionState> {
    try {
        const t = await getTranslations("textbooks.action");
        await requirePermission(Permissions.TEXTBOOK_UPDATE);

        const knowledgePointId = getStringValue(formData, "knowledgePointId");
        const prerequisiteKpId = getStringValue(formData, "prerequisiteKpId");
        const textbookId = getStringValue(formData, "textbookId");

        const parsed = DeletePrerequisiteSchema.safeParse({
            knowledgePointId,
            prerequisiteKpId,
        });
        if (!parsed.success) {
            return { success: false, message: t("invalidInput") };
        }

        // 归属校验：防止跨教材越权删除前置依赖
        const kpBelongs = await verifyKnowledgePointBelongsToTextbook(
            parsed.data.knowledgePointId,
            textbookId,
        );
        if (!kpBelongs) {
            return { success: false, message: t("kpNotBelong") };
        }
        const prereqBelongs = await verifyKnowledgePointBelongsToTextbook(
            parsed.data.prerequisiteKpId,
            textbookId,
        );
        if (!prereqBelongs) {
            return { success: false, message: t("kpNotBelong") };
        }

        await deletePrerequisite(parsed.data);
        revalidatePath(`/teacher/textbooks/${textbookId}`);
        return { success: true, message: t("prerequisiteDeleted") };
    } catch (e) {
        return handleActionError(e)
    }
}
