import { NextRequest, NextResponse } from "next/server";
import * as XLSX from "xlsx";
import { db } from "@/lib/db";
import { requirePageRole, resolveSchoolId, ApiError } from "@/lib/auth";
import { logAudit } from "@/lib/audit";
import { handleApiError } from "@/lib/api-helpers";
import { generateStudentCode, normalizeArabicName, GRADES } from "@/lib/constants";

/** الأعمدة المطلوبة في ملف الاستيراد (نفس ترويسة ملف التصدير) */
const TEMPLATE_HEADERS = [
  "الاسم",
  "الاسم بالإنجليزية",
  "الصف",
  "الشعبة",
  "ولي الأمر",
  "هاتف ولي الأمر",
  "العنوان",
  "القسط الكلي",
  "الخصم %",
  "تاريخ التسجيل",
  "ملاحظات",
];

const MAX_IMPORT_ROWS = 500;
const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB

/** تحميل قالب الاستيراد الجاهز */
export async function GET(req: NextRequest) {
  try {
    await requirePageRole("students", "ADMIN", "STAFF", "SUPER_ADMIN");
    const g5 = GRADES.find((g) => g.code === "G5");
    const example = [
      "أحمد محمد علي سالم",
      "Ahmed Mohammed Ali Salem",
      g5?.labelAr ?? "الصف الخامس الابتدائي",
      "أ",
      "محمد علي سالم",
      "7812345678",
      "",
      500000,
      0,
      new Date().toISOString().slice(0, 10),
      "",
    ];
    const ws = XLSX.utils.aoa_to_sheet([TEMPLATE_HEADERS, example]);
    ws["!Views"] = [{ RTL: true }];
    ws["!cols"] = [
      { wch: 34 }, { wch: 24 }, { wch: 22 }, { wch: 9 }, { wch: 28 },
      { wch: 16 }, { wch: 26 }, { wch: 12 }, { wch: 9 }, { wch: 13 }, { wch: 26 },
    ];
    const wb = XLSX.utils.book_new();
    XLSX.utils.book_append_sheet(wb, ws, "قالب الاستيراد");
    const buf = XLSX.write(wb, { type: "buffer", bookType: "xlsx" }) as Buffer;
    return new Response(new Uint8Array(buf), {
      headers: {
        "Content-Type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
        "Content-Disposition": `attachment; filename="students-import-template.xlsx"`,
        "Cache-Control": "no-store",
      },
    });
  } catch (err) {
    return handleApiError(err);
  }
}

interface ParsedRow {
  row: number;
  name: string;
  grade: string;
  classroom: string;
  status: "ready" | "imported" | "skipped" | "error";
  reason: string;
}

/** استخراج قيمة من الصف بأسماء أعمدة متعددة مقبولة */
function pickColumn(row: Record<string, unknown>, aliases: string[]): unknown {
  for (const a of aliases) {
    const v = row[a];
    if (v !== undefined && v !== null && String(v).trim() !== "") return v;
  }
  return undefined;
}

/** تحويل قيمة خلية إلى رقم */
function toNumber(v: unknown): number | null {
  if (v === undefined || v === null || String(v).trim() === "") return null;
  const n = Number(String(v).replace(/[,\s٫]/g, ""));
  return isNaN(n) ? null : n;
}

/** تحويل قيمة خلية إلى تاريخ (Date من Excel أو نص) */
function toDate(v: unknown): Date | null {
  if (v === undefined || v === null || String(v).trim() === "") return null;
  if (v instanceof Date) return isNaN(v.getTime()) ? null : v;
  if (typeof v === "number" && v > 20000 && v < 60000) {
    // رقم تسلسلي لتاريخ Excel
    return new Date(Math.round((v - 25569) * 86400 * 1000));
  }
  const s = String(v).trim().replace(/\//g, "-");
  const d = new Date(s);
  return isNaN(d.getTime()) ? null : d;
}

/** فحص الملف (mode=preview) أو الاستيراد الفعلي (mode=commit) */
export async function POST(req: NextRequest) {
  try {
    const user = await requirePageRole("students", "ADMIN", "STAFF", "SUPER_ADMIN");
    const schoolId = await resolveSchoolId(user);
    const form = await req.formData();
    const file = form.get("file");
    const mode = String(form.get("mode") || "preview") === "commit" ? "commit" : "preview";

    if (!(file instanceof File)) {
      throw new ApiError("الرجاء اختيار ملف الاستيراد أولاً", 400);
    }
    if (file.size > MAX_FILE_SIZE) {
      throw new ApiError("حجم الملف كبير جداً — الحد الأقصى 10 ميجابايت", 400);
    }

    let wb: XLSX.WorkBook;
    try {
      wb = XLSX.read(Buffer.from(await file.arrayBuffer()), { cellDates: true });
    } catch {
      throw new ApiError("تعذر قراءة الملف — تأكد أنه بصيغة Excel (xlsx) أو CSV", 400);
    }
    const sheet = wb.Sheets[wb.SheetNames[0]];
    if (!sheet) throw new ApiError("الملف لا يحتوي على أوراق عمل", 400);

    const rawRows = XLSX.utils.sheet_to_json<Record<string, unknown>>(sheet, { defval: "" });
    if (rawRows.length === 0) throw new ApiError("الملف فارغ — لا توجد صفوف للاستيراد", 400);
    if (rawRows.length > MAX_IMPORT_ROWS) {
      throw new ApiError(`عدد الصفوف ${rawRows.length} يتجاوز الحد الأقصى ${MAX_IMPORT_ROWS} صف في الملف الواحد`, 400);
    }

    // توحيد مفاتيح الترويسة (إزالة المسافات الزائدة)
    const rows: Record<string, unknown>[] = rawRows.map((r) => {
      const clean: Record<string, unknown> = {};
      for (const [k, v] of Object.entries(r)) clean[String(k).trim()] = v;
      return clean;
    });

    // خيارات الصفوف المقبولة: كود أو اسم (الثابت + المخصص من قاعدة البيانات — داخل المدرسة)
    const customGrades = await db.customGrade.findMany({ where: { schoolId } });
    const gradeOptions: { code: string; labels: string[] }[] = [
      ...GRADES.map((g) => ({ code: g.code, labels: [g.code.toUpperCase(), g.labelAr] })),
      ...customGrades.map((c) => ({ code: c.code, labels: [c.code.toUpperCase(), c.nameAr] })),
    ];
    const resolveGrade = (v: unknown): string | null => {
      const val = String(v ?? "").trim();
      if (!val) return null;
      const upper = val.toUpperCase();
      const hit = gradeOptions.find(
        (g) => g.code.toUpperCase() === upper || g.labels.some((l) => l.trim() === val)
      );
      return hit?.code ?? null;
    };

    const classroomRows = await db.classroom.findMany({ where: { schoolId }, select: { name: true } });
    const classroomSet = new Set(classroomRows.map((c) => c.name));

    // الطلبة الحاليون في نفس المدرسة لفحص التكرار
    const existing = await db.student.findMany({
      where: { isActive: true, schoolId },
      select: { nameAr: true, studentCode: true, grade: true, classroom: true },
    });
    const normalizedExisting = new Map<string, { studentCode: string; grade: string; classroom: string }>();
    for (const s of existing) normalizedExisting.set(normalizeArabicName(s.nameAr), s);

    const results: ParsedRow[] = [];
    const inFileNames = new Set<string>();
    const gradesInFile = new Set<string>();
    const validRows: {
      nameAr: string; nameEn: string; grade: string; classroom: string;
      guardianName: string; guardianPhone: string; guardianAddress: string | null;
      totalFee: number; discountPercent: number; registeredAt: Date; notes: string | null;
    }[] = [];

    for (let i = 0; i < rows.length; i++) {
      const r = rows[i];
      const excelRow = i + 2; // صف العناوين هو الأول
      const name = String(pickColumn(r, ["الاسم", "الاسم الرباعي", "اسم الطالب"]) ?? "").trim().replace(/\s+/g, " ");

      const fail = (reason: string) => {
        results.push({ row: excelRow, name: name || "—", grade: String(pickColumn(r, ["الصف", "المرحلة"]) ?? "").trim(), classroom: String(pickColumn(r, ["الشعبة", "الفصل"]) ?? "").trim(), status: "error", reason });
      };

      if (!name) { fail("الاسم فارغ — عمود «الاسم» إجباري"); continue; }
      const wordCount = name.split(" ").length;
      if (wordCount < 4) { fail(`الاسم الرباعي إجباري (${wordCount} كلمات فقط) — الاسم + الأب + الجد + اللقب`); continue; }

      // تكرار مع قاعدة البيانات أو داخل نفس الملف
      const normalized = normalizeArabicName(name);
      const dup = normalizedExisting.get(normalized);
      if (dup) {
        results.push({ row: excelRow, name, grade: dup.grade, classroom: dup.classroom, status: "skipped", reason: `مسجل مسبقاً بالكود ${dup.studentCode}` });
        continue;
      }
      if (inFileNames.has(normalized)) {
        results.push({ row: excelRow, name, grade: "", classroom: "", status: "skipped", reason: "مكرر داخل نفس الملف" });
        continue;
      }

      const gradeCode = resolveGrade(pickColumn(r, ["الصف", "المرحلة", "الصف الدراسي"]));
      if (!gradeCode) { fail("الصف غير معروف — اكتب اسم الصف كما يظهر في النظام (مثال: الصف الخامس الابتدائي)"); continue; }

      const classroom = String(pickColumn(r, ["الشعبة", "الفصل"]) ?? "").trim();
      if (!classroom) { fail("الشعبة فارغة — عمود «الشعبة» إجباري"); continue; }
      if (!classroomSet.has(classroom)) { fail(`الشعبة «${classroom}» غير موجودة في النظام — أضفها من صفحة الصفوف والشعب`); continue; }

      const guardianName = String(pickColumn(r, ["ولي الأمر", "اسم ولي الأمر"]) ?? "").trim();
      if (!guardianName) { fail("اسم ولي الأمر فارغ — إجباري"); continue; }
      const guardianPhone = String(pickColumn(r, ["هاتف ولي الأمر", "رقم هاتف ولي الأمر", "الهاتف", "رقم الهاتف"]) ?? "").trim();
      if (!guardianPhone) { fail("هاتف ولي الأمر فارغ — إجباري"); continue; }

      const totalFee = toNumber(pickColumn(r, ["القسط الكلي", "القسط"])) ?? 0;
      if (totalFee < 0) { fail("القسط الكلي لا يمكن أن يكون سالباً"); continue; }
      const discount = toNumber(pickColumn(r, ["الخصم %", "الخصم"])) ?? 0;
      if (discount < 0 || discount > 100) { fail("نسبة الخصم يجب أن تكون بين 0 و 100"); continue; }

      const regDate = toDate(pickColumn(r, ["تاريخ التسجيل", "تاريخ التسجيل الفعلي"]));
      if (regDate && regDate.getTime() > Date.now() + 5 * 60 * 1000) { fail("تاريخ التسجيل لا يمكن أن يكون مستقبلياً"); continue; }

      const nameEn = String(pickColumn(r, ["الاسم بالإنجليزية", "الاسم بالانجليزية", "الاسم الانجليزية"]) ?? "").trim() || name;

      inFileNames.add(normalized);
      gradesInFile.add(gradeCode);
      validRows.push({
        nameAr: name,
        nameEn,
        grade: gradeCode,
        classroom,
        guardianName,
        guardianPhone,
        guardianAddress: String(pickColumn(r, ["العنوان"]) ?? "").trim() || null,
        totalFee,
        discountPercent: Math.round(discount * 100) / 100,
        registeredAt: regDate ?? new Date(),
        notes: String(pickColumn(r, ["ملاحظات"]) ?? "").trim() || null,
      });
      results.push({ row: excelRow, name, grade: gradeCode, classroom, status: "ready", reason: "" });
    }

    if (mode === "preview") {
      const counts = {
        ready: results.filter((r) => r.status === "ready").length,
        skipped: results.filter((r) => r.status === "skipped").length,
        error: results.filter((r) => r.status === "error").length,
        imported: 0,
      };
      return NextResponse.json({ totalRows: rows.length, counts, rows: results });
    }

    // ---- الاستيراد الفعلي ----
    const year = new Date().getFullYear();
    const seqByGrade: Record<string, number> = {};
    for (const code of gradesInFile) {
      const prefix = `${code}-${year}-`;
      const last = await db.student.findFirst({
        where: { studentCode: { startsWith: prefix }, schoolId },
        orderBy: { studentCode: "desc" },
      });
      seqByGrade[code] = last ? parseInt(last.studentCode.split("-")[2] || "0", 10) + 1 : 1;
    }

    let imported = 0;
    for (const vr of validRows) {
      try {
        const code = generateStudentCode(vr.grade, year, seqByGrade[vr.grade]++);
        await db.student.create({
          data: {
            studentCode: code,
            nameAr: vr.nameAr,
            nameEn: vr.nameEn,
            grade: vr.grade,
            classroom: vr.classroom,
            guardianName: vr.guardianName,
            guardianPhone: vr.guardianPhone,
            guardianAddress: vr.guardianAddress,
            notes: vr.notes,
            totalFee: vr.totalFee,
            discountPercent: vr.discountPercent,
            registeredAt: vr.registeredAt,
            registeredById: user.id,
            schoolId,
          },
        });
        imported++;
        const res = results.find((r) => r.name === vr.nameAr && r.status === "ready");
        if (res) res.status = "imported";
      } catch {
        const res = results.find((r) => r.name === vr.nameAr && r.status === "ready");
        if (res) { res.status = "error"; res.reason = "فشل الحفظ — حاول مجدداً"; }
      }
    }

    const counts = {
      ready: 0,
      imported: results.filter((r) => r.status === "imported").length,
      skipped: results.filter((r) => r.status === "skipped").length,
      error: results.filter((r) => r.status === "error").length,
    };

    await logAudit(user, {
      action: "IMPORT",
      entity: "Student",
      entityId: null,
      details: `استيراد طلبة من ملف: ${rows.length} صف — نجح ${counts.imported}، تجاوز مكرر ${counts.skipped}، خطأ ${counts.error}`,
    });

    return NextResponse.json({ totalRows: rows.length, counts, rows: results });
  } catch (err) {
    return handleApiError(err);
  }
}
