import { Router } from "express";
import { prisma } from "../db.js";
import {
  parseJsonObject,
  toRegistrationStatusFa,
  type DraftPayloadShape,
} from "../db/mappers.js";
import { requireAuth } from "../middleware/auth.js";
import { resolveExamFromSelection } from "../services/examMatch.js";
import { config } from "../config.js";
import { createId } from "../utils/ids.js";
import { Prisma } from "@prisma/client";

export const registrationsRouter = Router();
registrationsRouter.use(requireAuth);

function computeStep(payload: DraftPayloadShape): number {
  const p = payload.personal;
  const e = payload.examSelection;
  const personalOk = Boolean(p.firstName?.trim() && p.lastName?.trim() && p.nid?.trim());
  const examOk = Boolean(e.exam?.trim());
  if (personalOk && examOk) {
    return 3;
  }
  if (personalOk) {
    return 2;
  }
  return 1;
}

registrationsRouter.put("/draft", async (req, res) => {
  if (!req.authUserId) {
    res.status(401).json({ message: "نیاز به ورود است." });
    return;
  }
  const userId = req.authUserId;
  const body = req.body as DraftPayloadShape & { extended?: DraftPayloadShape["extended"] };
  if (!body?.personal || !body?.examSelection) {
    res.status(400).json({ message: "ساختار فرم نامعتبر است." });
    return;
  }
  const existing = await prisma.registrationDraft.findUnique({ where: { userId } });
  const mergedExtended = {
    ...(existing ? parseJsonObject<DraftPayloadShape>(existing.payload, {} as DraftPayloadShape).extended ?? {} : {}),
    ...(body.extended ?? {}),
  };
  const payload: DraftPayloadShape = {
    personal: {
      firstName: String(body.personal.firstName ?? ""),
      lastName: String(body.personal.lastName ?? ""),
      nid: String(body.personal.nid ?? ""),
    },
    examSelection: {
      exam: String(body.examSelection.exam ?? ""),
      city: body.examSelection.city !== undefined ? String(body.examSelection.city) : undefined,
    },
    extended: Object.keys(mergedExtended).length ? mergedExtended : undefined,
  };
  const step = computeStep(payload);
  const draft = await prisma.registrationDraft.upsert({
    where: { userId },
    update: { step, payload: payload as unknown as Prisma.InputJsonValue },
    create: { id: createId(), userId, step, payload: payload as unknown as Prisma.InputJsonValue },
  });
  res.json({ draftId: draft.id, step });
});

registrationsRouter.post("/submit", async (req, res) => {
  if (!req.authUserId) {
    res.status(401).json({ message: "نیاز به ورود است." });
    return;
  }
  const userId = req.authUserId;
  const { draftId, acceptTerms } = req.body as { draftId?: string; acceptTerms?: boolean };
  if (!draftId || !acceptTerms) {
    res.status(400).json({ message: "شناسه پیش‌نویس و پذیرش قوانین الزامی است." });
    return;
  }
  const draft = await prisma.registrationDraft.findFirst({
    where: { id: draftId, userId },
  });
  if (!draft) {
    res.status(404).json({ message: "پیش‌نویس یافت نشد." });
    return;
  }
  const draftPayload = parseJsonObject<DraftPayloadShape>(draft.payload, {
    personal: { firstName: "", lastName: "", nid: "" },
    examSelection: { exam: "" },
  });
  const exam = await resolveExamFromSelection(draftPayload.examSelection.exam);
  const user = await prisma.user.findUnique({ where: { id: userId } });
  if (!user) {
    res.status(401).json({ message: "کاربر معتبر نیست." });
    return;
  }
  if (draftPayload.personal.nid.trim() !== user.nationalId) {
    res.status(400).json({ message: "کد ملی فرم باید با حساب کاربری یکسان باشد." });
    return;
  }
  const ext = draftPayload.extended ?? {};
  if (!ext.fatherName?.trim() || !ext.birthDate?.trim() || !ext.address?.trim()) {
    res.status(400).json({ message: "نام پدر، تاریخ تولد و آدرس برای ثبت‌نام الزامی است." });
    return;
  }

  const paidExists = await prisma.registration.findFirst({
    where: {
      userId,
      examId: exam.id,
      status: "PAID",
    },
  });
  if (paidExists) {
    res.status(400).json({ message: "برای این آزمون قبلاً ثبت‌نام و پرداخت انجام شده است." });
    return;
  }

  const payableAmount = exam.fee;
  const paymentUrl = `${config.frontendOrigin}/payment`;

  let registration = await prisma.registration.findFirst({
    where: {
      userId,
      examId: exam.id,
      status: { in: ["PENDING_APPROVAL", "PENDING_PAYMENT", "REJECTED"] },
    },
  });

  const { generateCandidateCode } = await import("../utils/codes.js");
  const candidateCode = registration?.candidateCode ?? generateCandidateCode();

  if (registration) {
    registration = await prisma.registration.update({
      where: { id: registration.id },
      data: {
        draftSnapshot: draftPayload as unknown as Prisma.InputJsonValue,
        payableAmount,
        paymentUrl,
        status: "PENDING_APPROVAL",
        rejectionReason: null,
      },
    });
  } else {
    registration = await prisma.registration.create({
      data: {
        id: createId(),
        userId,
        examId: exam.id,
        draftSnapshot: draftPayload as unknown as Prisma.InputJsonValue,
        status: "PENDING_APPROVAL",
        payableAmount,
        candidateCode,
        resultState: "UNKNOWN",
        paymentUrl,
      },
    });
  }

  res.json({
    registrationId: registration.id,
    status: toRegistrationStatusFa(registration.status),
    payableAmount,
    paymentUrl,
  });
});

registrationsRouter.get("/:registrationId/payment-summary", async (req, res) => {
  if (!req.authUserId) {
    res.status(401).json({ message: "نیاز به ورود است." });
    return;
  }
  const { registrationId } = req.params;
  const registration = await prisma.registration.findFirst({
    where: { id: registrationId, userId: req.authUserId },
    include: { exam: true },
  });

  if (!registration) {
    res.status(404).json({ message: "ثبت‌نام یافت نشد." });
    return;
  }
  const snap = parseJsonObject<DraftPayloadShape>(registration.draftSnapshot, {
    personal: { firstName: "", lastName: "", nid: "" },
    examSelection: { exam: "" },
  });
  const fullName = `${snap.personal.firstName} ${snap.personal.lastName}`.trim();
  res.json({
    registration: {
      id: registration.id,
      fullName,
      nationalId: snap.personal.nid,
      examTitle: registration.exam.title,
      examDate: registration.exam.date,
      status: toRegistrationStatusFa(registration.status),
    },
    charges: [{ label: "هزینه ثبت‌نام آزمون", amount: registration.exam.fee, type: "normal" as const }],
    totalPayable: registration.payableAmount,
  });
});
